Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Critical Storage Collision

Summary

The UUPS upgrade from LevelOne to LevelTwo contains critical storage layout mismatches that will corrupt the contract's state. The v2 contract reorders/deletes state variables from v1 and fails to maintain storage layout compatibility, violating upgrade safety requirements.

Vulnerability Details

Storage Layout Analysis:

Slot LevelOne (v1) LevelTwo (v2)
0 principal principal
1 schoolFees inSession (bool)
2 inSession (bool) sessionEnd
3 reviewTime (immutable) bursary
4 sessionEnd cutOffScore
5 bursary isTeacher (mapping base)
6 cutOffScore isStudent (mapping base)
7 isTeacher (mapping base) studentScore (mapping base)
8 isStudent (mapping base) listOfStudents (array base)
9 studentScore (mapping base) listOfTeachers (array base)
10 reviewCount (mapping base) usdc (IERC20)

Key Issues:

  1. Critical Misalignment: sessionEnd moves from slot 4→2, bursary from 5→3, and cutOffScore from 6→4

  2. Missing Variables: v2 doesn't account for v1's reviewTime, reviewCount, and lastReviewTime mappings

  3. Type Corruption: schoolFees (uint256) in v1 is overwritten by inSession (bool) in v2

  4. Token Address Risk: usdc in v2 occupies slot 9 which overlaps with v1's mapping storage

Impact

High Severity: Upgrade will permanently corrupt all state variables, leading to:

  • Incorrect access control (principal address may change)

  • Broken financial logic (bursary amounts corrupted)

  • Lost student/teacher records (mappings point to wrong storage)

  • Bricked token transfers (USDC address overwritten)

  • Irreversible damage to contract state

Tools Used

  1. Manual review

Recommendations

  1. Maintain Identical Storage Layout:

    • Keep all v1 variables in exact same order

    • Append new variables only at the end

  2. Correct v2 Implementation:

contract LevelTwo is Initializable {
// PRESERVE EXACT V1 STORAGE LAYOUT
address principal;
uint256 schoolFees;
bool inSession;
uint256 public immutable reviewTime = 1 weeks;
uint256 public sessionEnd;
uint256 public bursary;
uint256 public cutOffScore;
mapping(address => bool) public isTeacher;
// ... keep all original mappings/arrays ...
// ONLY ADD NEW VARIABLES AFTER EXISTING ONES
uint256 public newL2Variable; // <-- Safe addition
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

storage collision

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.