A manually reviewed external total is being used for this incident.
Source0xba15e9b644685cb845af18a738abd40c6bcd78edBase0xf9A88E0E6152C1b403B8B162E1790D96e08d201fBSC0x5240B03Be5Bc101A0082074666dd89aD883e1f9dEthereumAcross Base, BSC, and Ethereum, an adversary cluster of fresh EOAs and helper contracts abused public router entrypoints that already held large token allowances from three treasury-style holders. In one attacker-crafted transaction per chain, these routers executed transferFrom calls that pulled USDC, USDT, and WBTC out of the treasuries and into attacker-controlled EOAs or LP positions. The core root cause is architectural: routers that were approved as spenders for large treasury token balances exposed public entrypoints that allowed arbitrary EOAs to trigger transferFrom from those treasuries without enforcing any treasury-owner or governance authorization, violating a basic treasury-spend invariant.
The affected flows involve three independent treasuries and their tokens:
0xba15e9b644685cb845af18a738abd40c6bcd78ed, with large allowances granted to routers 0x616000e384Ef1C2B52f5f3A88D57a3B64F23757e and 0xdC3914cA7b18A2BF41B43A263258B71e32296D7D.0xf9A88E0E6152C1b403B8B162E1790D96e08d201f, with a large allowance to router 0x353713e18f997494D00Dd80aCD350759A5e726A2.0x5240B03Be5Bc101A0082074666dd89aD883e1f9d, with an effectively infinite allowance to router 0xD83d960deBEC397fB149b51F8F37DD3B5CFA8913.All three tokens implement standard ERC20/BEP20-style approval and transferFrom semantics. For example, the Base USDC implementation is a FiatTokenV2_2 contract compiled from the Circle USDC codebase:
0x8f28a7f604f1b3890c2275eec54cd7deb40935183a856074c0a06e4b5f72f25a// Collected USDC implementation for Base (FiatTokenV2_2)
// Origin: verified source for token 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
contract FiatTokenV2_2 is FiatTokenV2_1 {
// ...
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes memory signature
) external whenNotPaused {
_permit(owner, spender, value, deadline, signature);
}
// standard ERC20 allowance / transferFrom semantics are inherited from FiatTokenV1/V2
}
On BSC, BEP20USDT exposes the usual ERC20-compatible interface, including allowance, approve, and transferFrom:
// Collected BEP20USDT interface (BSC)
interface IBEP20 {
function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address _owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
Ethereum WBTC uses the standard OpenZeppelin-style ERC20 implementation with allowance and transferFrom, as seen in the collected source under seed/1/0x2260fa.../src/Contract.sol. In all three cases, any contract holding sufficient allowance can invoke transferFrom(holder, recipient, amount) without additional on-chain authorization checks.
Routers on each chain are long-lived public contracts:
0x616000e384Ef1C2B52f5f3A88D57a3B64F23757e and 0xdC3914cA7b18A2BF41B43A263258B71e32296D7D (aggregator-style routers that hold a 2^256-1 USDC allowance from the Base treasury holder).0x353713e18f997494D00Dd80aCD350759A5e726A2 (aggregator/router used for USDT routing on BSC).0xD83d960deBEC397fB149b51F8F37DD3B5CFA8913 (router that holds an infinite WBTC allowance from the WBTC treasury holder and routes into Uniswap V3).Disassembly for these routers (under artifacts/root_cause/data_collector/iter_2/contract/.../cast_disassemble.txt) shows aggregator-style entrypoints that interpret calldata and ultimately issue ERC20 transferFrom calls using the router’s allowances. For example, the Ethereum router runtime bytecode clearly embeds the WBTC address and the ERC20 transferFrom selector:
// Extract from runtime_bytecode.json for router 0xD83d96... (Ethereum)
{
"result": "0x6101e0...12261ee7...6377633a...70a08231...23b872dd...000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88..."
}
The adversary operates under an Anyone-Can-Take (ACT) model: any unprivileged EOA that knows about these allowances and router entrypoints can deploy a helper contract and send the same calldata to realize the same transferFrom-based treasury spends, without any special keys, whitelists, or private orderflow.
The incident is classified as an ACT-style attack. The vulnerability is architectural: public routers with very large treasury token allowances can perform transferFrom-based spends from treasury holders without binding those spends to any governance-controlled or treasury-operations-only caller.
Invariant (treasury-spend safety). For each treasury holder H and ERC20 token T, any on-chain debit T.transferFrom(H, X, amount) that spends treasury funds must be initiated only by an authorized governance or treasury-operations component and must not be triggerable by arbitrary EOAs solely via pre-granted allowances.
Breakpoint (violating call path). In the router entrypoints used on Base, BSC, and Ethereum, the contracts call token.transferFrom(holder, recipient, amount) using the router’s allowance from the treasury holder, without checking that msg.sender is an authorized treasury operator or that the holder address matches msg.sender. Once a large allowance is granted, any EOA can deploy a helper and invoke these entrypoints to route arbitrary treasury spends to attacker-controlled recipients.
The root cause is therefore the combination of:
2^256-1 allowances to public routers.transferFrom from these treasuries solely based on allowance.Helper contracts deployed by the adversary (0xcCE2..., 0xDE59..., 0x5c9288...) simply exploit this design; they are not the root cause themselves. They forward calls into the routers with carefully crafted calldata that causes the routers to spend from the treasuries.
At the ACT opportunity block heights
41289841 (tx 0xc15df1d1...),77381400 (tx 0x35540e9e...),24313234 (tx 0x8f28a7f6...),the following facts hold and are fixed on-chain:
0xba15e9b644685cb845af18a738abd40c6bcd78ed.0xf9A88E0E6152C1b403B8B162E1790D96e08d201f.0x5240B03Be5Bc101A0082074666dd89aD883e1f9d.0x2ce6311ddae708829bc0784c967b7d77d19fd779, token address 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.0x55d398326f99059ff775485246999027b3197955.0x2260fac5e5542a773aa44fbcfedf7c193bc2c599.0x616000e384Ef1C2B52f5f3A88D57a3B64F23757e and 0xdC3914cA7b18A2BF41B43A263258B71e32296D7D.0x353713e18f997494D00Dd80aCD350759A5e726A2.0xD83d960deBEC397fB149b51F8F37DD3B5CFA8913.Approval and authorization logs collected in artifacts/root_cause/data_collector/iter_3/contract/*/logs/approval_permit_* show that, prior to the attacker-crafted profit transactions, each treasury holder has given the corresponding router a very large allowance:
2^256-1 from 0xba15... to router 0x6160....0xf9A8... to router 0x3537....0x5240... to router 0xD83d96....These allowances create a standing capability for the routers to call transferFrom against the treasury holders. Since routers are publicly callable, any EOA that knows the function selectors and encodings can exercise this capability.
Disassembly and runtime bytecode for the routers (data_collector iter_2) show aggregator-style entrypoints:
0x87395540 on routers 0x6160.../0xdC39... parses calldata describing token routes and invokes transferFrom on FiatTokenV2_2 USDC using the router’s allowance from 0xba15....0x3537... exposes routing entrypoints that call BEP20USDT.transferFrom on token 0x55d3... from 0xf9A8... to arbitrary recipients.0xD83d96... exposes selector 0x6377633a, which in the seed trace for tx 0x8f28a7f6... routes WBTC and PAXG via Uniswap V3, invoking WBTC.transferFrom(0x5240..., helper, 36.91897652 WBTC) based solely on the router’s allowance.In all three cases, there are no conditional checks tying the spend to a treasury-operator-only caller. msg.sender is simply the attacker helper or EOA that calls the router. The router’s authority to spend treasury funds is bounded only by the allowance, not by caller identity.
Each chain uses a fresh EOA and helper pair:
0x6caad74121bf602e71386505a4687f310e0d833e (nonce 0).0xcCE2E1a23194bD50d99eB830af580Df0B7e3225b.0x4bcd06648a9315a233229b634b89011009f7b195 (nonce 0).0xDE5957A205008fFfcDDFC44cC01535823dF15b00.0xe3e73f1e6ace2b27891d41369919e8f57129e8ea (nonce 0).0x5c92884dFE0795db5ee095E68414d6aaBf398130.Seed traces for the three attacker transactions show a consistent pattern: contract creation for the helper, followed by an immediate call from the helper into the router, all within a single attacker-crafted transaction:
# Seed transaction trace for Base tx 0xc15df1d1... (excerpt)
# Origin: artifacts/root_cause/seed/8453/0xc15df1d1.../trace.cast.log
depth:1 OPCODE: "CREATE" # helper 0xcCE2... deployed by EOA 0x6caad...
...
depth:2 OPCODE: "CALL" # helper calls router 0x6160... selector 0x87395540
...
depth:3 OPCODE: "CALL" # router calls USDC.transferFrom(0xba15..., 0x6caad..., amount)
The BSC and Ethereum traces under seed/56/.../trace.cast.log and seed/1/.../trace.cast.log show analogous deploy-and-call-router sequences, ending in ERC20 transfer logic.
Balance diff artifacts confirm concrete token movements.
On Base (USDC), balance_diff.json for tx 0xc15df1d1... shows:
// Seed balance diff for Base USDC tx 0xc15df1d1...
{
"erc20_balance_deltas": [
{
"token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"holder": "0xba15e9b644685cb845af18a738abd40c6bcd78ed",
"delta": "-13342433169249"
},
{
"token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"holder": "0x6caad74121bf602e71386505a4687f310e0d833e",
"delta": "13342433169249"
}
]
}
On BSC (USDT), balance_diff.json for tx 0x35540e9e... shows:
// Seed balance diff for BSC USDT tx 0x35540e9e...
{
"erc20_balance_deltas": [
{
"token": "0x55d398326f99059ff775485246999027b3197955",
"holder": "0xf9a88e0e6152c1b403b8b162e1790d96e08d201f",
"delta": "-25791508841389255775657"
},
{
"token": "0x55d398326f99059ff775485246999027b3197955",
"holder": "0x04028e5eaf698f93929e33015ca42b9c5eabd46a",
"delta": "25791508841389255775657"
}
]
}
On Ethereum (WBTC), balance_diff.json for tx 0x8f28a7f6... focuses on native balances, while iter_3 ERC20-focused traces and WBTC Transfer logs show a debit of 36.91897652 WBTC from 0x5240... and a corresponding credit into a Uniswap V3 PAXG/WETH LP position (tokenId 1181114) controlled by helper 0x5c9288....
These deltas match the narrative in root_cause.json, which summarizes the cluster-level profit as:
0x6caad7... from treasury holder 0xba15....0x04028e5eAF698F93929E33015ca42b9c5EaBd46a from treasury holder 0xf9A8....0x5c9288....Native-balance deltas (ETH/BNB) show only small gas expenditures from the adversary EOAs on each chain (on the order of 10^-3 native units), so the net portfolio change for the adversary cluster is strictly positive across Base, BSC, and Ethereum.
The ACT opportunity is fully described in act_opportunity in root_cause.json and is supported by seed/index.json and the iter_* artifacts. For any new adversary:
approve(holder -> router, amount)).msg.sender values to cause transferFrom(holder, recipient, amount) using router-held allowances.Given these conditions, any unprivileged EOA can realize the same success predicate as the observed adversary cluster by replaying the pattern (deploy helper, call router entrypoint, consume treasury allowances) without any special access.
Root_cause.json identifies the minimal adversary-related cluster with explicit reasoning:
0x6caad74121bf602e71386505a4687f310e0d833e (nonce-0): deploys helper 0xcCE2... and receives the USDC outflow from 0xba15... in the seed tx.0xcCE2E1a23194bD50d99eB830af580Df0B7e3225b: called by the EOA, in turn calls routers 0x6160.../0xdC39... to route the treasury USDC allowance into the EOA.0x4bcd06648a9315a233229b634b89011009f7b195 (nonce-0): deploys helper 0xDE59... and pays gas for the BSC exploit tx.0xDE5957A205008fFfcDDFC44cC01535823dF15b00: calls router 0x3537... to move approximately 25,791.5088 USDT from treasury holder 0xf9A8... to profit EOA 0x04028....0x04028e5eAF698F93929E33015ca42b9c5EaBd46a: receives the USDT outflow from the BSC treasury holder.0xe3e73f1e6ace2b27891d41369919e8f57129e8ea (nonce-0): deploys helper 0x5c9288..., originates the seed tx, and pays gas; ultimately controls the Uniswap V3 LP position funded by stolen WBTC.0x5c92884dFE0795db5ee095E68414d6aaBf398130: receives WBTC via router 0xD83d96... and mints a Uniswap V3 PAXG/WETH position (tokenId 1181114) holding the WBTC-equivalent value.Victim candidates are:
0xba15e9b644685cb845af18a738abd40c6bcd78ed (labeling not externally verified in this dataset).0xf9A88E0E6152C1b403B8B162E1790D96e08d201f.0x5240B03Be5Bc101A0082074666dd89aD883e1f9d.These accounts are supported by the seed metadata and data_collector address-activity windows, which show the treasuries’ approval history and the adversary EOAs’ fresh nonce patterns.
Root_cause.json decomposes the adversary flow into three stages, all of which can be reproduced by any unprivileged EOA with the same pre-state.
Stage 1: Pre-existing treasury approvals to public routers.
0xba15... → 0x6160... (Base USDC).0xf9A8... → 0x3537... (BSC USDT).0x5240... → 0xD83d96... (Ethereum WBTC).artifacts/root_cause/data_collector/iter_3/contract/*/logs/approval_permit_* show allowances at 2^256-1 or similarly large values at or before the exploit blocks.Stage 2: Adversary helper deployment and setup.
0xc15df1d1... at block 41289841 (chainid 8453) – EOA 0x6caad... deploys helper 0xcCE2... and helper immediately calls routers 0x6160.../0xdC39....0x35540e9e... at block 77381400 (chainid 56) – EOA 0x4bcd... deploys helper 0xDE59... and calls router 0x3537....0x8f28a7f6... at block 24313234 (chainid 1) – EOA 0xe3e7... deploys helper 0x5c9288... and calls router 0xD83d96... (selector 0x6377633a).trace.cast.log) for each tx show contract creation followed by router calls from the helpers within a single transaction.Stage 3: Treasury spends and profit realization.
USDC.transferFrom(0xba15..., 0x6caad..., amount) using the pre-existing allowance, debiting the treasury and crediting the adversary EOA.BEP20USDT.transferFrom(0xf9A8..., 0x04028..., amount) to move the USDT balance to the adversary.WBTC.transferFrom(0x5240..., 0x5c9288..., 36.91897652 WBTC), after which the helper mints a Uniswap V3 PAXG/WETH position (tokenId 1181114) holding the WBTC-equivalent value.artifacts/root_cause/seed/*/balance_diff.json and WBTC transfer logs/Uniswap V3 position logs in data_collector/iter_3 show debits from the treasury holders and credits to adversary-controlled addresses or LP positions.Throughout all stages, there are no privileged roles, admin keys, or whitelists involved in the attacker-crafted transactions; they rely purely on public allowances and router code.
The impact is fully captured in token-level balance deltas across the three chains:
0xba15e9b644685cb845af18a738abd40c6bcd78ed loses USDC (delta -13342433169249 in token units) to adversary EOA 0x6caad74121bf602e71386505a4687f310e0d833e.0x6caad7... gains the same amount, funded entirely by the treasury holder via router 0x6160....0xf9A88E0E6152C1b403B8B162E1790D96e08d201f loses 25,791.508841389255775657 USDT (delta -25791508841389255775657 units).0x04028e5eAF698F93929E33015ca42b9c5EaBd46a gains the same USDT amount.0x5240B03Be5Bc101A0082074666dd89aD883e1f9d loses 36.91897652 WBTC, which is routed into a Uniswap V3 LP position (tokenId 1181114) whose owner is helper 0x5c9288... controlled by the adversary EOA.Across all chains, treasury-style holders lose control of significant USDC, USDT, and WBTC balances to an unprivileged adversary cluster. Because the mechanism only depends on public allowances and router behavior, the same pattern can be repeated by any other attacker as long as similar router allowances remain in place.
This analysis and root cause conclusion are supported by the following on-chain artifacts and code:
artifacts/root_cause/seed/8453/0xc15df1d1.../{metadata.json,balance_diff.json,trace.cast.log}.artifacts/root_cause/seed/56/0x35540e9e.../{metadata.json,balance_diff.json,trace.cast.log}.artifacts/root_cause/seed/1/0x8f28a7f6.../{metadata.json,balance_diff.json,trace.cast.log}.artifacts/root_cause/seed/56/0x55d39832.../src/Contract.sol, seed/56/0xbb4cdb9c....artifacts/root_cause/seed/1/0x2260fac5.../src/Contract.sol, seed/1/0xc02aaa39....artifacts/root_cause/data_collector/iter_2/contract/*/{runtime_bytecode.json,cast_disassemble.txt}.artifacts/root_cause/data_collector/iter_2/address/*/txlist_normal.json for treasury holders, routers, and profit EOAs.artifacts/root_cause/data_collector/iter_3/contract/*/logs/approval_permit_*.artifacts/root_cause/data_collector/iter_3/contract/1/0xc36442b4.../logs/position_lifecycle_tokenId_1181114.json.Together, these artifacts provide a deterministic, reproducible evidence trail for the ACT opportunity, the adversary cluster, the invariant violation, and the realized losses.