Reproduced Exploit

Reentrant `mintMultiple` callback — untrusted external call

mintMultiple computes state and then calls every caller-supplied asset. A malicious token's transferFrom callback re-enters mint, proving that the no-guard ordering exposes temporary accounting state.

Jan 2021Ethereumreentrancy2 min read

Loss

Reentrant asset callback can mutate vault accounting before mint completion

Chain

Ethereum

Category

reentrancy

Date

Jan 2021

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: 18201-reentrancy-and-untrusted-contract-call-in-mintmultiple-diffi. Standalone Foundry PoC and full write-up: 18201-reentrancy-and-untrusted-contract-call-in-mintmultiple-diffi_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/reentrancy/single-function · vuln/dependency/unsafe-external-call

Reproduction: self-contained synthetic Foundry reduction; see output.txt.

Key info#

FieldValue
LossReentrant asset callback can mutate vault accounting before mint completion
Vulnerable contractVaultCore.mintMultiple
Attacker EOA0x1111111111111111111111111111111111111111
Attack contractCallbackAsset via Exploit
Attack txExploit.run()
Chain / block / dateEthereum model · block 0 · 2021-01
Compilersolc 0.8.24 (synthetic)
Bug classReentrancy through arbitrary transferFrom

TL;DR#

mintMultiple computes state and then calls every caller-supplied asset. A malicious token's transferFrom callback re-enters mint, proving that the no-guard ordering exposes temporary accounting state.

Background#

The Origin Dollar finding notes that unsupported assets are skipped in pricing but still called in the transfer loop. The reduction isolates that callback boundary and the missing nonReentrant guard.

The vulnerable code#

SOLIDITY
for (uint256 i; i < assets.length; ++i) {
    ICallbackAsset(assets[i]).transferFrom(msg.sender, address(this), amounts[i]);
}

Root cause#

The vault trusts an arbitrary token contract before settling the temporary imbalance and mint state. No reentrancy guard protects the externally callable minting family.

Preconditions#

  • The caller can supply an asset address.
  • The supplied asset implements a callback-capable transferFrom.

Attack walkthrough#

  1. Exploit passes CallbackAsset to mintMultiple.
  2. CallbackAsset.transferFrom calls VaultCore.mint while the outer call is active.
  3. The Proof event at output.txt:380 shows rebaseCount = 1 from the callback.

Diagrams#

sequenceDiagram participant E as Exploit participant V as VaultCore participant T as Malicious asset E->>V: mintMultiple(assets) V->>T: transferFrom() T->>V: mint() re-entry V-->>E: outer call continues with corrupted ordering

Remediation#

Validate asset membership and non-zero amounts before any transfer, add nonReentrant to mint, mintMultiple, and redemption functions, and avoid arbitrary callbacks where possible.

How to reproduce#

BASH
cd evm-hack-registry/18201-reentrancy-and-untrusted-contract-call-in-mintmultiple-diffi_exp
forge test -vvvvv

Sources#

Reference: https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf


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.