In liquidate(), _redeem_collateral (which makes an external transfer call) executes before _burn_dsc. Between these two operations, the user's collateral is reduced but their debt is unchanged, creating an intermediate state with a worse health factor that a callback-enabled token can exploit.
_redeem_collateral calls extcall IERC20(token_collateral_address).transfer(_to, amount_collateral) at line 253. If the collateral token has a transfer callback (ERC777 tokensReceived, ERC1363 onTransferReceived), control passes to the liquidator during step 1.
At that point, the user's collateral is reduced but debt is unchanged, so their HF is even worse. The liquidator can re-enter liquidate() against the same user, triggering cascading liquidations that extract more collateral than intended.
No function in dsc_engine.vy uses @nonreentrant.
The companion function redeem_collateral_for_dsc (line 94-103) correctly orders burn before redeem, confirming this is an oversight rather than a design choice.
Likelihood:
The README says "someone could fork this codebase, swap out WETH & WBTC for any basket of assets they like." Forks using ERC777/ERC1363 tokens are explicitly in scope.
No @nonreentrant guard exists on any function.
Impact:
A malicious liquidator can drain a user's entire collateral through cascading reentrant liquidations.
With standard WETH/WBTC this is unexploitable, but the codebase is designed for forking with arbitrary tokens.
Attack sequence with ERC777 collateral:
User has 10 tokens collateral ($20,000), 10,000 DSC debt, HF = 0.95e18 (liquidatable)
Attacker calls liquidate(token, user, 1000e18) covering $1,000 debt
_redeem_collateral transfers 1,100 worth of collateral to attacker via extcall IERC20.transfer
ERC777 tokensReceived fires on attacker's contract
Attacker re-enters liquidate(token, user, 1000e18) — user now has less collateral, same debt, even worse HF
Step 5 repeats until user's collateral is drained
Outer calls return, _burn_dsc executes for each, but collateral is already gone
Add @nonreentrant and reorder to burn debt before redeeming collateral:
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.