# Allbridge CCTP: forged message credits phantom deposit, drains Router

Allbridge CCTPTokenMessenger credited forged CCTP messages without verifying a real USDC mint, letting an attacker redeem phantom deposits from the Router for ~190k USDC.

- Payout: Real-world hack
- Severity: critical
- Program: AllbridgeCCTP
- Credited: DeFiHackLabs
- Disclosed: 2026-08-19
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-08/AllbridgeCCTP_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260819-allbridgecctp
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:oracle-manipulation vuln:signature-replay

**Target:** Allbridge Core Router + CCTPTokenMessenger on Base
**Root cause:** receiveCctpMessage reads amount/feeExecuted/sourceSender/messageHash from fixed byte offsets and credits receivedMessages without checking that a real USDC mint or balance change occurred; both guards (destinationCaller, sourceSender) are attacker-satisfiable from public getters. Circle's MessageTransmitterV2 attests only that a message was submitted, not that value moved.
**Steps:**
1. Read remoteTokenMessengers[5] and domainToChainId to satisfy sourceSender guard
2. Author a CCTP v2 message with destinationCaller = messenger address, sourceSender = remoteTokenMessengers[sourceChainId], amount = 1e12 (1,000,000 USDC), feeExecuted, and hookData[0:32] = Router._calculateMessageHash(nonce, recipient, token, amount, sourceChain, CHAIN_ID)
3. Get the message attested by Circle's off-chain attester (attests submission, not value)
4. Call CCTPTokenMessenger.receiveCctpMessage(message, attestation) to credit receivedMessages[messageHash] = amount - feeExecuted
5. Flash-loan (1,000,000 - Router balance) USDC from Aave V3, push into Router
6. Call Router.receiveToken(...) to redeem 999,000 USDC to attacker recipient
7. Repay flash loan (809,248.445619 USDC incl. 404.422012 premium), keep 189,751.554381 USDC
**How found:** Code review of CCTPTokenMessenger.receiveCctpMessage revealed it reads fields at fixed offsets and credits receivedMessages without verifying a real mint; both guards are satisfiable from public getters, and Circle's generic attestation primitive signs submission not value transfer.
**Exploitation:** Attacker forged a CCTP v2 message shaped like a 1,000,000 USDC deposit, had it attested by Circle (which only attests submission), relayed it through Allbridge's CCTPTokenMessenger to credit a phantom messageHash, then flash-loaned 808,844 USDC from Aave V3 to top up the Router so its 999,000 USDC payout succeeded, repaying the loan and netting 189,751.554381 USDC.
**Insight:** When a bridge credits a message hash based on parsed fields, check whether it verifies an actual token mint/balance delta; if the underlying attestation primitive signs arbitrary caller-authored payloads, the credit is forgeable. Also check that solvency guards (receivedTokenAmount > 0) aren't the only check before payout.
