This report details a functional vulnerability in the LevelTwo.sol
contract. The graduate()
function, intended as a reinitializer(2)
to be called upon upgrading from LevelOne.sol
, is currently empty. This omission means that critical student graduation logic, specifically the requirement that "Any student who doesn't meet the cutOffScore
should not be upgraded," is not enforced during the transition to Level Two. Consequently, all students from Level One, regardless of their academic performance, are carried over to Level Two, violating a core project invariant.
In UUPS upgradeable contracts, reinitializer
functions are invoked once when a proxy is upgraded to a new implementation version. Their purpose is to perform necessary state migrations, initialize new variables, or execute setup logic specific to the new version.
The LevelTwo.sol
contract defines a graduate()
function:
This function is currently empty.
The project documentation specifies a key invariant:
Any student who doesn't meet the cutOffScore should not be upgraded
The graduateAndUpgrade()
function in LevelOne.sol handles wage payments and authorizes the upgrade but does not perform any filtering of students based on their scores. Therefore, the graduate()
reinitializer in LevelTwo.sol
is the logical place to implement this student filtering logic. Its current empty state means this crucial step is missed.
The necessary state variables (listOfStudents
, studentScore
mapping, and cutOffScore
) are part of the shared storage between LevelOne.sol
and LevelTwo.sol
and are accessible to the graduate() function (assuming storage layout compatibility is otherwise addressed).
Setup:
LevelOne.sol
is deployed via a proxy and initialized.
A cutOffScore
(e.g., 70) is set when the session starts.
Two students are enrolled:
Student A, with studentScore[StudentA]
= 60 (below cutOffScore
).
Student B, with studentScore[StudentB]
= 80 (at or above cutOffScore
).
Both Student A and Student B are present in the listOfStudents
array.
Upgrade Process:
The Principal
calls graduateAndUpgrade()
in LevelOne.sol
, targeting LevelTwo.sol
. This function pays wages and authorizes the upgrade but does not modify listOfStudents
.
The proxy is upgraded to the LevelTwo.sol
implementation.
As part of the upgradeToAndCall
mechanism, the graduate()
function in LevelTwo.sol
is executed.
Outcome:
Since graduate()
is empty, no filtering logic is applied.
Both Student A and Student B remain in the listOfStudents
array within the state now managed by LevelTwo.sol
.`.
This violates the invariant that Student A (who did not meet the cutOffScore
) should not have been "upgraded."
Violation of Core Business Logic: The system fails to adhere to a clearly documented rule regarding student progression.
Incorrect System State:LevelTwo.sol
will operate with an incorrect list of students, including those who should not have graduated.
Potential Unfairness/Exploitation: If Level Two introduces new features or benefits for "graduated" students, those who did not meet the criteria would unfairly gain access.
Misleading Functionality: The name graduate()
implies specific actions that are not performed, potentially confusing developers or auditors about the system's behavior.
Manual Code Review
The graduate()
reinitializer function in LevelTwo.sol
must be implemented to filter the listOfStudents
based on the cutOffScore
. Students who do not meet the cutOffScore
should be removed from the active student list for Level Two.
A common approach is to build a new list containing only the students who meet the graduation criteria and then replace the existing listOfStudents
array.
Proposed Conceptual Code Change for LevelTwo.sol
:
All students are graduated when the graduation function is called as the cut-off criteria is not applied.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.