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.

Apr 2024Otheruntagged3 min read

Chain

Other

Category

untagged

Date

Apr 2024

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

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.

Loading fork state…

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-registry mirror.


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#

ImpactHIGHmergeTranches / 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
ProtocolGondi — multi-source NFT lending
Vulnerable coderepayLoan_baseLoanChecks after id-changing mergeTranches
Bug classLoan-id invalidation / MEV front-run DoS on repayment
FindingCode4rena — Gondi, 2024-04 · #35212 · reporter zhaojie
Reportcode4rena.com/reports/2024-04-gondi
SourceAuditVault
StatusAudit finding — confirmed high (lender motivation); mitigated by limiting id-changing call paths
Compiler^0.8.24 (PoC)

TL;DR#

  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.

The vulnerable code#

SOLIDITY
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#

  1. Borrower has a 2-tranche loan; NFT escrowed; repay would succeed.
  2. Attacker/lender calls mergeTranches (permissionless in the audited code) collapsing to one tranche and a new loanId.
  3. Borrower's repayLoan(oldId, …) fails InvalidLoanError.
  4. Liquidation on the new single-tranche loan claims the NFT to the remaining lender.

Diagrams#

sequenceDiagram participant B as Borrower participant Mem as Mempool participant L as LenderAttacker participant MSL as MultiSourceLoan B->>Mem: repayLoan oldId L->>MSL: mergeTranches front-run MSL->>MSL: newId written, oldId deleted Mem->>MSL: repayLoan oldId MSL-->>B: revert InvalidLoanError L->>MSL: liquidateLoan newId MSL->>L: NFT transferred

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#


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

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.