Crypto exploits

AllbridgeCCTP exploit analysis

On 2026-08-19, an attacker on Base presented a forged CCTP v2 message attested off-chain to the Allbridge Core Router's messenger and extracted ~189,751.55 USDC in a single transaction funded by an Aave V3 flash loan.

Reported loss
~189,751.554381 USDC, per DeFiHackLabs
Occurred
Logged

Logged as “2026-08-19: Phantom Deposit Via Unverified Message Attestation on AllbridgeCCTP”.

Analysis2 min read

The Allbridge Core Router on Base at 0xaA119F7442eCC28b9a8F236707ADA8362CFF24fF integrates Circle CCTP v2 through the Allbridge CCTP messenger at 0xf9b710e427bf4d93598e0f80a84de22c7ad9b577 and Circle's MessageTransmitterV2 at 0x81D40F21F12A8F0E3252Bccb954D722d4c464B64. The messenger's receiveCctpMessage(message, attestation) relays an attested Circle message through MessageTransmitterV2.receiveMessage and credits receivedMessages[messageHash] = amount - feeExecuted, reading amount, feeExecuted, sourceSender, and messageHash directly out of fixed byte offsets in the message body. It never checks that the message caused a real USDC mint or any balance change. After the receiveMessage call it does only the subtraction and the mapping write.

Its two guards are both attacker-satisfiable from public state. destinationCaller (message[108:140]) must equal the messenger's own address, which is public. sourceSender (message[248:280]) must equal remoteTokenMessengers[sourceChainId], where sourceChainId = domainToChainId[sourceDomain]. Both mappings are public getters, so the attacker just reads remoteTokenMessengers[5] and copies it into the forged body.

Circle's MessageTransmitterV2 is a generic attestation primitive: sendMessage emits an arbitrary caller-authored payload and Circle's off-chain attester signs that the message was submitted, not that any value moved. Anyone can author a payload shaped like a CCTP deposit, have it attested, and relay it here.

The Allbridge Router's receiveToken(...) treats receivedTokenAmount(messageHash) > 0 as its only solvency check (confirmed in source) and pays out amountAfterFee to the caller-chosen recipient. The credited messageHash is the first word of the forged message's hookData, which the attacker precomputes as Router._calculateMessageHash(nonce, recipient, token, amount, sourceChain, CHAIN_ID) for a redeem of its own choosing.

The attacker (EOA 0x2419432344b0B892E592b2601B98eaE702Ba360e) ran the drain in 0x9f906fcd8fceaa6745e8d1c004861dcfa9b5e6a893fe1e8c5d0013a4e982e6a8 on Base block 50,157,345. The forged CCTP v2 message declared a 1,000,000 USDC deposit. The Router paid out 999,000 USDC (1,000,000 minus the 0.1 percent feeBp) and retained exactly 1,000 USDC. The attacker flash-loaned 1,000,000 - Router balance = 808,844.023607 USDC from Aave V3 and pushed it into the Router so the 999,000 transfer succeeded, then repaid 809,248.445619 USDC including the 404.422012 premium. Net kept: 189,751.554381 USDC.

The Router already held 191,155.976393 USDC at block-1; the PoC does not deal that in, it is real forked state from a legitimate ~191,112 USDC CCTP inflow that minted into the Router about six seconds earlier.

The fix is for the messenger to verify that the attested message actually moved value on the receiver chain, or to require that the redeemed amount not exceed the messenger's own live USDC balance at the time of redemption. The deeper fix is to bind the messenger's destinationCaller to the recipient the Router will later redeem to, so a value transfer cannot be relayed without a matching redeem.

Sources read (3)

Other exploits

Query every incident yourself — free, no signup

Updated 14 Oct 2026. Figures are as reported by the sources listed above and are not independently verified.