This report reviews the security of two smart contracts, LevelOne
and LevelTwo
, designed for a decentralized learning environment with USDC-based payments, role-based access (principal, teachers, students), and upgradeable functionality. Both contracts are structured with OpenZeppelin's upgradeable framework.
While the structure is modular and extensible, the current implementations reveal critical vulnerabilities and incomplete logic that may lead to contract takeover, misuse of roles, inconsistent data states, and broken payment mechanics.
Type: Critical
Location: LevelOne.sol
, LevelTwo.sol
Description: Neither contract contains an initialize()
function to set initial values such as principal
, usdc
, or role assignments. In an upgradeable (proxy-based) context, this exposes a contract to untrusted initialization (SWC-118).
Consequence: An attacker can initialize the contract and assume complete control, including claiming roles, setting token contracts, or draining funds.
graduate()
Function Without Access Control (LevelTwo.sol
)
Type: High
Location: LevelTwo.sol
Description: The graduate()
function is publicly callable and only protected by reinitializer(2)
. Without access control, it becomes a latent threat if additional upgrade logic is introduced.
Consequence: Unauthorized invocation of logic in future upgrades or reinitialization attacks.
LevelOne.sol
, LevelTwo.sol
)
Type: Medium
Location: listOfTeachers
, listOfStudents
arrays
Description: When roles are assigned, no checks prevent re-adding the same address to the arrays, even if isTeacher
or isStudent
is already true.
Consequence: Role inflation. If used for wage distribution or iterations, duplicates can lead to overpayments or incorrect behavior.
LevelTwo.sol
)
Type: Medium
Description: Despite including SafeERC20
, a bursary
, and wage constants (TEACHER_WAGE_L2
, PRINCIPAL_WAGE_L2
), there are no functions to deposit, withdraw, or transfer USDC to teachers or the principal.
Consequence: Token logic is non-functional; bursary cannot be utilized or distributed securely.
LevelTwo.sol
)
Type: Low
Variables: inSession
, sessionEnd
, cutOffScore
, studentScore
Description: These variables exist without functional use in the current version.
Consequence: Misleading or dead code. If relied on by future features, this can lead to broken behavior.
LevelTwo.sol
)
Type: Low
Description: A PRECISION
constant of 100 is defined, which may not align with the USDC tokenโs 6 decimal precision or other ERC20 tokens.
Consequence: Calculation inaccuracies during financial distribution.
Vulnerability | Severity | Impact Summary |
---|---|---|
Uninitialized contracts | ๐ด Critical | Total contract takeover by attacker |
Public graduate() | ๐ด High | Uncontrolled access to future upgrades |
Duplicate role entries | ๐ Medium | Role inflation and state inconsistency |
No USDC handling | ๐ Medium | Broken bursary and payment mechanics |
Unused session variables | ๐ก Low | Unmaintainable code; future bugs |
Fixed precision mismatch | ๐ก Low | Financial miscalculations |
Manual Code Review
Slither (static analysis)
VSCode Solidity Plugin
OpenZeppelin Contracts Reference
SWC Registry
Add an initialize()
method to properly set principal, token addresses, and initial roles:
graduate()
to Authorized RolesWhen assigning new teachers/students:
Example: deposit bursary
And payments:
Include mechanisms to start and end sessions:
Instead of hardcoded precision, use:
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.