Reproduced Exploit

Gondi — distribute() lacks access control (Pool accounting corruption)

1. distribute() is permissionless. 2. Attacker crafts a loan: principalAddress = Junk, sole lender = Pool. 3. Junk is transferred to the Pool; loanLiquidation does totalAssets += _received. 4. Attacker with a dust USDC deposit withdraws ~2× real USDC, draining victims.

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: 35205-h-03-function-distribute-lacks-access-control-allowing-anyon. Standalone Foundry PoC and full write-up: 35205-h-03-function-distribute-lacks-access-control-allowing-anyon_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/access-roles · vuln/direct-drain · vuln/liquidation-logic

Reproduction: self-contained Foundry PoC with only forge-std — no fork, no RPC. Full trace: output.txt. PoC: test/35205-h-03-function-distribute-lacks-access-control-allowing-anyon.sol.


Key info#

ImpactHIGH — anyone calls LiquidationDistributor.distribute with a junk ERC20 as principalAddress and the Pool as lender; Pool credits junk as real assets; dust depositor drains victim USDC
ProtocolGondi — NFT lending
Vulnerable codeLiquidationDistributor.distribute — no access control; Pool.loanLiquidation treats _received as asset inflow without a token check
Bug classMissing access control → accounting inflation → fund theft
FindingCode4rena — Gondi, 2024-04 · #35205 · reporter zhaojie
Reportcode4rena.com/reports/2024-04-gondi
SourceAuditVault
StatusAudit finding — confirmed and mitigated (caller check added)
Compiler^0.8.24 (PoC)

TL;DR#

  1. distribute() is permissionless.
  2. Attacker crafts a loan: principalAddress = Junk, sole lender = Pool.
  3. Junk is transferred to the Pool; loanLiquidation does totalAssets += _received.
  4. Attacker with a dust USDC deposit withdraws ~2× real USDC, draining victims.

The vulnerable code#

SOLIDITY
/// @> VULN: no access control
function distribute(address originator, Loan memory loan, uint256 amount) external {
    MockERC20 token = MockERC20(loan.principalAddress);
    token.transferFrom(msg.sender, address(this), amount);
    ...
    Pool(lender).loanLiquidation(..., _sent, ...);
}

Fix: only allow Loan contracts to call distribute.

Root cause#

distribute trusts caller-supplied loan struct fields. The Pool's loanLiquidation never receives principalAddress, so it cannot reject junk tokens — any amount reported as _received inflates share pricing.

Attack walkthrough#

  1. Victim deposits 1000 USDC; attacker deposits 1 USDC dust.
  2. Attacker calls distribute with 1000 Junk → Pool as lender.
  3. totalAssets becomes 2001 while real USDC is still 1001.
  4. Attacker withdraws 1 share → ~1.999 USDC stolen excess.

Diagrams#

sequenceDiagram participant Attacker participant Dist as LiquidationDistributor participant Pool Attacker->>Dist: distribute fake loan principal=Junk Dist->>Pool: transfer Junk + loanLiquidation received Note over Pool: totalAssets inflated Attacker->>Pool: withdraw dust shares Pool-->>Attacker: excess real USDC

Impact#

Direct theft of depositor USDC/WETH via share-price inflation. Permissionless surface means any address can spam and corrupt accounting.

Taxonomy#

  • genome: liquidation-logic, variant, direct-drain, access-roles, liquidation-underwater, timestamp-dependence
  • sector: lending, stable, staking-pool, token
  • severity: high
  • platform: code4rena

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.