DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Potential Overflow in Loop Counter Leading to Infinite Loop

Summary

The getUserDeposits function in the PerpetualVault contract uses a uint8 type for its loop counter while iterating over a user's deposits. Since uint8 can only hold values up to 255, if a single user accumulates more than 255 deposits, the function will enter an infinite loop due to counter overflow, causing transactions to fail with out-of-gas errors.

Vulnerability Details

In the getUserDeposits function:

function getUserDeposits(address user) external view returns (uint256[] memory depositIds) {
uint256 length = EnumerableSet.length(userDeposits[user]);
depositIds = new uint256[](length);
for (uint8 i = 0; i < length;) {
depositIds[i] = EnumerableSet.at(userDeposits[user], i);
unchecked { i = i + 1; } } }

The vulnerability stems from:

  1. Using uint8 for the loop counter i, which can only represent values from 0 to 255

  2. Comparing this counter against length, which is a uint256 that could be larger than 255

  3. Incrementing the counter inside an unchecked block, which bypasses Solidity's default overflow checks

  4. When i reaches 255 and is incremented, it will overflow to 0 without any error, creating an infinite loop

When a user has more than 255 deposits, the loop will:

  • Iterate through deposits 0-255 normally

  • When attempting to increment i from 255 to 256, it will overflow to 0

  • Since 0 < length, the loop will continue and process deposit 0 again

  • This creates an infinite loop, eventually causing an out-of-gas error

Impact

  • Users who accumulate more than 255 deposits will be unable to retrieve their complete deposit history

  • The function will always revert with an out-of-gas error for these users

  • This blocks access to critical vault functionality for long-term power users

  • Front-end interfaces using this function will break for affected users

  • The issue may affect institutional users or automated strategies that make frequent deposits

  • Since deposits accumulate over time, this creates a ticking time bomb where users eventually lose access

  • If any outer systems rely on that function it will be DoS-ed for them too

Tools Used

  • Manual code review

Recommendations

Change the type of the loop counter to match the type of the length variable:

=> function getUserDeposits(address user) external view returns (uint256[] memory depositIds) {
uint256 length = EnumerableSet.length(userDeposits[user]);
depositIds = new uint256[](length);
for (uint256 i = 0; i < length;) {
depositIds[i] = EnumerableSet.at(userDeposits[user], i);
unchecked {
i = i + 1;
}
}
}

This ensures that the loop counter can handle the same range of values as the length variable, preventing the potential overflow and infinite loop, regardless of how many deposits a user has accumulated.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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

Give us feedback!