liquidate sends collateral before burning debt and no function is @nonreentrant, creating a reentrancy window (defense-in-depth)Severity: Low · Impact: Low · Likelihood: Low
liquidate should follow checks-effects-interactions: reduce the victim's debt (effect) before paying out collateral (interaction). Instead it calls _redeem_collateral — which performs an external transfer of collateral to the liquidator — before _burn_dsc reduces the victim's debt. No engine function is marked @nonreentrant, and Vyper 0.4.0 applies no default lock.
A liquidator using a collateral token with a transfer hook (ERC777-style) can therefore re-enter liquidate while the victim still shows the full, un-burned debt, so the starting_user_health_factor < MIN gate and the ending > starting improvement check are both evaluated against stale state.
Likelihood:
Requires a collateral token with a transfer callback — not the case for standard WETH/WBTC, but reachable under the protocol's "any basket of assets" fork claim.
Impact:
The reentrancy does not currently yield a profit: total coverage is capped at the victim's actual debt by the _burn_dsc underflow, so a re-entering liquidator seizes no more collateral than a single legitimate liquidation (verified in the PoC). It remains a latent safety issue that would become exploitable under small future changes to the accounting or bonus logic.
Save the block below as tests/poc_m2.py inside the cloned repo and run mox test tests/poc_m2.py. Both the hook collateral token and the re-entering liquidator are compiled inline via boa.loads. The measured seizure equals a fair single liquidation (≈6.11 tokens for $100 of debt at $18, 10% bonus), confirming the window exists but is not profitable today.
Follow checks-effects-interactions (burn the debt before transferring collateral) and add an explicit reentrancy guard to the state-changing entry points.
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.