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

Reentrancy Vulnerability in PerpetualVault's `_handleReturn` Function Due to Insecure State Management

Summary

The _handleReturn function in the PerpetualVault contract contains a reentrancy vulnerability caused by unsafe ordering of state changes relative to external token transfers. This violates the Checks-Effects-Interactions pattern, allowing potential reentrancy attacks if malicious tokens (e.g., ERC777) are used as collateral.


Vulnerability Details*

Affected Code

  • Function: _handleReturn(uint256,bool,bool)

  • Lines: L1129-L1156

Root Cause

The function performs external token transfers (_transferToken) before updating critical state variables (totalShares, depositInfo via _burn). This creates a window for reentrancy:

function _handleReturn(...) internal {
...
_transferToken(depositId, amount); // External call first
emit Burned(...);
_burn(depositId); // State update after
}

Key Risk Factors

  1. External Calls Before State Updates:

    • _transferToken triggers token transfers (e.g., ERC777 callbacks) before _burn updates totalShares or deletes depositInfo.

  2. Stale State Exposure:

    • During reentrancy, attackers can exploit stale totalShares or depositInfo values to manipulate vault state.


Impact

  • Theft of Funds: An attacker could reenter the contract to mint new shares or withdraw additional funds.

  • Share Manipulation: Stale totalShares values could allow attackers to inflate their share of the vault.

  • Severity: High/Critical (depends on collateral token standards in use).


Proof of Concept (PoC)

Attack Scenario

  1. Malicious Token Setup:

    • Attacker deposits an ERC777 token (with callback hooks) as collateral.

  2. Withdraw Trigger:

    • Attacker calls withdraw, initiating _handleReturn.

  3. Reentrancy During Transfer:

    • During _transferToken, the ERC777 token’s tokensReceived callback reenters the contract.

  4. Exploit Stale State:

    • The reentrant call invokes deposit, which calculates shares using outdated totalShares (not yet updated by _burn).

    • Attacker mints extra shares, diluting other users’ holdings.

Sample Code

// Malicious ERC777 token
contract AttackToken is ERC777 {
PerpetualVault vault;
function tokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes memory data,
bytes memory operatorData
) external override {
// Reenter the vault during withdrawal
vault.deposit(1); // Uses stale totalShares
}
}

Recommended Mitigation

1. Adhere to Checks-Effects-Interactions

Update state variables before making external calls:

function _handleReturn(...) internal {
...
_burn(depositId); // Update state first
emit Burned(...);
_transferToken(depositId, amount); // External call last
}

2. Use Reentrancy Guards

Apply the nonReentrant modifier to all state-changing functions (even if indirectly called):

function _handleReturn(...) internal nonReentrant {
...
}
Updates

Lead Judging Commences

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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