Reproduced Exploit

Autonomint: borrower downside protection is recovered into the whole CDS pool

Nov 2024Otheruntagged2 min read

Chain

Other

Category

untagged

Date

Nov 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: 734. Standalone Foundry PoC and full write-up: 45464-h-11-borrower-withdrawing-at-a-loss-will-cause-losses-for-cd_exp in the evm-hack-registry mirror.


Vulnerability classes: liquidation-logic · reward-accounting · integer-bounds · locked-funds

Reproduction: deploys the REAL audited Autonomint protocol (full Core_logic + lib at Sherlock snapshot 0d324e04d4c0ca306e1ae4d4c65f0cb9d681751b) with minimal real doubles only for the opaque external venues (Ionic, WETH, Synthetix, RedStone oracle) and the repo's own EndpointV2Mock LayerZero stack. No mainnet fork.

Root cause#

When a borrower withdraws while underwater, BorrowLib.withdraw increases omniChainData.downsideProtected and the CDS realizes that loss by subtracting it from totalCdsDepositedAmount (CDS.withdraw / CDSLib). When the price later recovers, the protection is credited back to the pool at large (divided by the full totalCdsDepositedAmount) rather than to the specific depositor that funded it. The aggregate therefore drifts below the sum of the individual deposits and a later depositor cannot be made whole.

Vulnerable sources: src/lib/BorrowLib.sol (downside protection increase) and src/Core_logic/CDS.sol (withdraw, downside realization + return-amount calculation).

Exploit walkthrough (real numbers)#

  1. CDS depositor #1 deposits 6,000 USDT.
  2. A borrower deposits 1 ETH at $1,000.
  3. Price drops to $900; the borrower withdraws at a loss — this adds ~100 USDa of downside protection that is deducted from the pool aggregate (0.5 ETH is paid to a fresh EOA).
  4. A second borrower deposits 1 ETH at $900; price recovers to $1,000.
  5. CDS depositor #2 deposits 6,000 USDT.
  6. Both depositors put in 6,000 each (12,000 total) at the same net price, yet totalCdsDepositedAmount reads 11,900 — a permanent 100 USDa shortfall that strands the later depositor.

test/…_exp.sol asserts totalCdsDepositedAmount < 12,000e6.

sequenceDiagram participant C1 as CDS depositor 1 participant B as Borrower participant C2 as CDS depositor 2 participant P as CDS pool C1->>P: deposit 6000 B->>P: borrow (price 1000 -> 900) B->>P: withdraw at loss (downside -100 from pool) Note over P: price recovers to 1000 C2->>P: deposit 6000 Note over P: aggregate = 11900 < 12000 (100 stuck)

Reproduction#

BASH
_shared/run-poc/run_poc.sh 45464-h-11-borrower-withdrawing-at-a-loss-will-cause-losses-for-cd_exp -vvvvv

Sources & further analysis#

Reproductions & code

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.