Algo Ssstablecoinsss

AI First Flight #2
Beginner FriendlyDeFi
EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

Reentrancy in liquidate function


Reentrancy in liquidate() Allows Complete Collateral Drainage

Description

  • Liquidators should partially liquidate underwater users, allowing them to recover remaining collateral after debt repayment.

  • The liquidate() function calls _redeem_collateral() (external transfer) before _burn_dsc() (debt update), enabling reentrancy via callback tokens to repeatedly liquidate before debt state updates.

@external
def liquidate(collateral: address, user: address, debt_to_cover: uint256):
// ... checks ...
@> self._redeem_collateral( // External call FIRST - reentrancy point
collateral,
token_amount_from_debt_covered + bonus_collateral,
user,
msg.sender,
)
@> self._burn_dsc(debt_to_cover, user, msg.sender) // Debt updated AFTER

Risk

Likelihood:

  • Admin whitelists ERC777 or upgradeable token with transfer hooks as collateral

  • Attacker deploys contract exploiting transfer callback to reenter liquidate()

Impact:

  • Underwater users lose 100% of collateral in single transaction instead of partial liquidation

  • Attacker repeatedly extracts collateral + 10% bonus until position fully drained

Proof of Concept

// Attacker contract receives collateral via ERC777 tokensReceived callback
function tokensReceived(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) external {
// Victim's debt NOT updated yet - health factor still broken
if (attackCount < 3) {
attackCount++;
dscEngine.liquidate(collateral, victim, debtAmount);
}
}

Victim has 200 collateral and 100 debt. Attacker calls liquidate() and reenters 3 times via callback, extracting 55 collateral each iteration (165 total) instead of a single 55 partial liquidation.

Recommended Mitigation

  • from snekmate.utils import reentrancy_guard

  • initializes: reentrancy_guard

    @external

  • @nonreentrant
    def liquidate(collateral: address, user: address, debt_to_cover: uint256):

Add a @nonreentrant decorator to prevent reentrant calls during liquidation.


Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 14 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!