Originally published at Ankr Bridge Exploit: Forged Receipts Drained $304K
On 9 November 2026, an attacker sent five withdraw() transactions to Ankr's Ethereum cross-chain bridge and walked away with roughly $304,500 in staking tokens. According to SlowMist, all five requests pointed at the same legitimate Optimism transaction, and each one carried a valid signature from the bridge's trusted consensus signer. The bridge checked the signature, paid out, and never asked whether the claimed source-chain event actually matched the amounts being withdrawn.
This is a useful case study because the headline loss is small, but the design flaw is the one that sinks much larger bridges: a signature proves that someone approved a message, not that the message is true.
What Happened
Blockaid flagged an ongoing exploit of the Ankr bridge on X at about 08:42 UTC on 9 November, with roughly $292,000 already gone. SlowMist later put the loss at about $304,500. The gap is mostly timing and token pricing: Blockaid counted what had left at the time of its alert, while SlowMist's figure came from its later analysis.
The reported facts, cross-checked across SlowMist, Blockaid and independent coverage:
| Item | Value |
|---|---|
| Chain | Ethereum mainnet (source reference on Optimism) |
| Vulnerable contract | 0xc437DF90B37C1dB6657339E31BfE54627f0e7181 (Ankr: Bridge) |
| Attacker (tx sender) | 0x9A88Dd45AE846A979705c9cFdfD0f229e592D703 |
| Recipient | 0x119D250b82C1cf5345dF5912EFb4B1a4107a1Aa6 |
| Attack transactions | 5 successful withdraw() calls, about 08:09 to 08:12 UTC |
| Reused source transaction (Optimism) | 0x02e805b51beb4ed39e6a66ffcbdf9060cf008b3c3f0e827d0d357dfa115e7d4a |
| Loss | About $304.5K (SlowMist); about $292K at Blockaid's first count |
The five Ethereum transactions listed by SlowMist are 0x7310af5d...88df, 0x90c56336...c891, 0xde2d5b45...9b5c, 0x91ba1a9c...2886 and 0x46e20d4c...dad0.
The reused Optimism transaction was a tiny deposit, about 0.0044 ankrETH, made on 3 November and, according to press coverage of SlowMist's analysis, already redeemed on Ethereum the same day. Tokens reported as withdrawn include ankrETH, ankrPOL, ANKR, and the older aMATICb and aETHb reward tokens. One outlet priced the recipient's three main assets at about $216K of ankrETH, $56K of ankrPOL and $31K of ANKR, with the two older tokens unpriced.
The Root Cause: A Signature Without a Binding Check
A lock-and-release bridge works in two halves. A user deposits on the source chain, an off-chain set of signers observes the deposit and signs a receipt, and the destination contract releases funds when it sees a receipt with a valid signature.
SlowMist's description of the failure is specific: the attacker built five forged receipts that referenced one real Optimism transaction but changed the recipient, token and withdrawal amount. Every receipt still passed signature verification, so withdraw() released assets without independently verifying the receipt against the actual source-chain event.
Two separate weaknesses are visible in that description:
- Signed data was not tied to source-chain facts. If the contract had recomputed or committed to what the deposit really contained (token, amount, recipient), changed fields would have failed.
- A processed source transaction could be referenced again. The reference deposit had already been redeemed. A replay guard keyed on the source transaction, or on a unique deposit ID, should reject repeats.
A simplified model (illustrative, not Ankr's code)
The snippet below is a deliberately simplified sketch of the vulnerable pattern. It is not Ankr's actual implementation, which we have not reviewed line by line.
// SIMPLIFIED, ILLUSTRATIVE ONLY struct Receipt { bytes32 srcTxHash; uint256 logIndex; address recipient; address token; uint256 amount; } function withdraw(Receipt calldata r, bytes calldata sig) external { // Only checks that the trusted signer approved these exact bytes require(_recover(keccak256(abi.encode(r)), sig) == trustedSigner, "bad sig"); // Missing: is r.srcTxHash already processed? // Missing: do token / amount / recipient match the real deposit? IERC20(r.token).transfer(r.recipient, r.amount); } A safer version marks each deposit ID as consumed before paying out, and derives the amounts from a commitment the signers could not have signed for a different value.
// SIMPLIFIED, ILLUSTRATIVE ONLY mapping(bytes32 => bool) public processed; function withdraw(Receipt calldata r, bytes calldata sig) external { bytes32 id = keccak256(abi.encode(r.srcTxHash, r.logIndex)); require(!processed[id], "already processed"); processed[id] = true; require(_verifyThresholdSigs(r, sig), "bad sigs"); IERC20(r.token).safeTransfer(r.recipient, r.amount); } Even this version only moves the trust question: if the signing key signs a bad receipt, the contract pays. That is why the open question below matters.
The Unanswered Question: Where Did the Signatures Come From?
SlowMist states that the origin of the unauthorized signatures is still under investigation, and signer compromise has not been confirmed. We want to be equally careful. A forged receipt with a valid signature has only a few explanations: a signing key or signing service was accessed, a signing service was tricked into signing attacker-supplied data, or the signing logic itself was flawed. The public sources do not say which.
There is one circumstantial detail. Blockaid's thread reports that between roughly 02:08 and 04:06 UTC the same attacker emptied five Ankr operator wallets across Ethereum, Arbitrum and Linea, consolidated the funds, and used them to fund the relayer that submitted the bridge calls. That suggests prior access to operational infrastructure, but nobody has confirmed how it was gained, and we are not drawing conclusions from it.
At the time of writing, Ankr had not published a statement or post-mortem. An advisory from 0xCERT reported that bridge withdrawals were paused afterwards, while an earlier on-chain reading around 08:49 UTC had still shown the pause flag unset. Treat the current state as unconfirmed and follow Ankr's official channels.
Lessons for Bridge and Messaging Builders
Bind every field to a verifiable source. A signature should cover a message whose contents the destination can check, or at least a unique ID that maps to exactly one recorded deposit with fixed token, amount and recipient.
Track consumption of source events. Each deposit should be redeemable once. A mapping of processed IDs costs very little gas next to the loss it prevents.
Do not rely on a single signer. SlowMist's wording refers to a trusted consensus signer. Threshold signing across independent keys and independent infrastructure makes one compromised host insufficient.
Separate hot operational wallets from bridge inventory authority. If operator wallets are swept, that should not be enough to authorize release of locked reserves.
Rate-limit and cap withdrawals. Five withdrawals unlocked what Blockaid described as the bridge's locked inventory within about three minutes. Per-window caps and an automatic pause on anomalous outflows turn a drain into an incident you can respond to.
Monitor and rehearse the pause. Detection came from outside security firms rather than from a built-in circuit breaker. A pause that is documented, tested and wired to alerts is worth more than one that exists only as a flag.
What Users Should Do
If you hold assets that were bridged through Ankr, watch the project's official channels before moving anything, and treat unsolicited recovery or refund offers as phishing. This analysis is technical commentary, not financial advice.
Sources
- Blockaid alert on X: ongoing exploit, five withdraw calls, about $292K at first count
- SlowMist TI alert via AiCoin: root cause, addresses, attack and reused source transactions, about $304.5K
- The Crypto Times: timeline, token breakdown, operator-wallet sweeps
- 0xCERT-2026-0328: advisory with transaction hashes and indicators
- SlowMist Hacked database: incident record
- Etherscan: Ankr Bridge contract: contract identification
Related Reading
We have covered similar verification failures before: the zkLink Nova forged root exploit, the WAX bridge negative fee exploit and the Sui bridge stale withdrawals case.
Closing Thoughts
The Ankr incident reduces to one question every bridge must answer on-chain: when a trusted signer says "release these funds", what independent fact does the contract check before it does? If the answer is "nothing", the signing infrastructure becomes the only line of defense. If you build or integrate bridges, talk to our team or review our audit pricing to have receipt verification, replay protection and signer design reviewed before an attacker does it for you.


