Reproduced Exploit
Gondi — front-running repayLoan via loanId rotation
1. repayLoan requires _loan.hash() == _loans[loanId]. 2. mergeTranches writes a new loanId and delete _loans[old]. 3. Front-running a repay with merge makes the old id invalid → repay reverts. 4. Near expiry the lender forces liquidation; with a single merged tranche the NFT is claimed directly.
Chain
Other
Category
untagged
Date
Apr 2024
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 35212-h-10-the-attackers-front-running-repayloans-so-that-the-debt. Standalone Foundry PoC and full write-up: 35212-h-10-the-attackers-front-running-repayloans-so-that-the-debt_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/frontrun · vuln/liquidation-logic · vuln/dos
Reproduction: self-contained Foundry PoC with only
forge-std— no fork, no RPC. Full trace: output.txt. PoC: test/35212-h-10-the-attackers-front-running-repayloans-so-that-the-debt.sol.
Key info#
| Impact | HIGH — mergeTranches / addNewTranche / refinance rotate loanId and delete the old entry; a lender can front-run repayLoan so the borrower cannot repay, then liquidate and seize the NFT |
| Protocol | Gondi — multi-source NFT lending |
| Vulnerable code | repayLoan → _baseLoanChecks after id-changing mergeTranches |
| Bug class | Loan-id invalidation / MEV front-run DoS on repayment |
| Finding | Code4rena — Gondi, 2024-04 · #35212 · reporter zhaojie |
| Report | code4rena.com/reports/2024-04-gondi |
| Source | AuditVault |
| Status | Audit finding — confirmed high (lender motivation); mitigated by limiting id-changing call paths |
| Compiler | ^0.8.24 (PoC) |
TL;DR#
repayLoanrequires_loan.hash() == _loans[loanId].mergeTrancheswrites a new loanId anddelete _loans[old].- Front-running a repay with merge makes the old id invalid → repay reverts.
- Near expiry the lender forces liquidation; with a single merged tranche the NFT is claimed directly.
The vulnerable code#
function repayLoan(...) external {
// ...
_baseLoanChecks(loanId, loan); // @> VULN if loanId was rotated
}
function mergeTranches(...) external {
_loans[loanId] = loanMergedTranches.hash();
delete _loans[_loanId]; // invalidates in-flight repay with old id
}
// FIX: do not delete old id / block id-changing calls near expiry / restrict caller
Root cause#
Loan identity is a mutable mapping key. Any function that rotates the key without borrower consent can race a repay (or refinance/liquidate) mempool transaction. A hostile lender is highly motivated near expiry: block repayment, then foreclose the NFT.
Attack walkthrough#
- Borrower has a 2-tranche loan; NFT escrowed; repay would succeed.
- Attacker/lender calls
mergeTranches(permissionless in the audited code) collapsing to one tranche and a new loanId. - Borrower's
repayLoan(oldId, …)failsInvalidLoanError. - Liquidation on the new single-tranche loan claims the NFT to the remaining lender.
Diagrams#
Impact#
Borrowers can be prevented from repaying near expiry and lose NFT collateral. Severity raised to high once lender motivation was recognized. Mitigation limited who can rotate loan identity and under what conditions.
Taxonomy#
- genome: liquidation-logic, frontrun, use-reentrancy-guard, dos-resistance, frontrun-exposure, liquidation-underwater, reentrancy-guard, timestamp-dependence
- sector: lending, nft, nft-lending
- severity: high
- platform: code4rena
- impact: mev/frontrun
Sources#
- AuditVault finding #35212
- Code4rena report 2024-04-gondi
- Reduced from code-423n4/2024-04-gondi@b9863d7
mergeTranches/repayLoan/_baseLoanChecks
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 35212-h-10-the-attackers-front-running-repayloans-so-that-the-debt_exp (evm-hack-registry mirror).
- AuditVault finding: 35212-h-10-the-attackers-front-running-repayloans-so-that-the-debt.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.