THORChain ETH Router Fake-Deposit Refund Drain (2021-07-22)

  • Name: THORChain ETH Router fake-deposit refund drain
  • Date: 2021-07-22
  • Protocol: THORChain / Bifrost / ETH Router
  • Chain: Ethereum + THORChain
  • Category: bridge deposit-signal mismatch / event ambiguity / memo-triggered refund drain / unbacked outbound release
  • Loss: about $8M, including roughly 1.67M USDC, 990,137 USDT, 20.87M XRUNE, 56,104 SUSHI, 966.62 ALCX, and 6.91 YFI
  • Summary: THORChain’s second July 2021 ETH-router exploit worked because Bifrost accepted a deposit-looking router event as proof that real user assets had arrived when the underlying call path had not created the economic state Bifrost assumed. THORChain’s own postmortem says the attacker created a fake router setup, called returnVaultAssets() with a small amount of ETH while that router path was defined as an Asgard vault, and thereby caused the real Router to forward ETH and emit what Bifrost interpreted as a normal deposit carrying a malicious memo. The healthy boundary should have been only the canonical router-authored deposit artifact that proves user custody change may author inbound truth; instead, a router-adjacent vault-return path was still able to mint deposit meaning. THORChain then followed its ordinary bad memo -> refund logic and released real ERC-20 assets from vault inventory even though the inbound deposit premise was fake.
  • Trigger / entry point:
    • THORChain’s Ethereum-side Router and Bifrost listener had to agree on what counted as a real inbound deposit.
    • Bifrost consumed router-side event data and memo semantics as if they reliably represented real user deposit intent and custody change.
    • A router-adjacent returnVaultAssets() path remained reachable through an attacker-controlled contract arrangement that the system did not model as adversarial deposit fabrication.
    • THORChain’s normal memo handling would refund a transaction when the memo was malformed or otherwise invalid.
  • Root cause:
    • The core failure was not stolen keys or forged validator signatures. It was source-side authenticity drift: event looked like a deposit was treated as equivalent to user really deposited assets under the expected path.
    • Bifrost did not fully account for how smart-contract event context could be manipulated when the router interacted with attacker-controlled contracts.
    • THORChain’s postmortem preserves the sharper mechanical boundary: a returnVaultAssets()-style path, with the router defined as an Asgard-vault-like destination, could still produce a deposit-looking event even though the surrounding call path was not the canonical user-deposit lane that should have been allowed to author inbound truth.
    • In other words, THORChain let a router-adjacent event stand in for the one thing that mattered: a router-owned custody artifact proving that user value had actually arrived under the intended deposit path.
    • Once Bifrost accepted that event and memo as genuine, THORChain’s refund logic turned a fake inbound into a real outbound.
  • Exploit path:
    1. The attacker funded EOA 0x8c1944fac705ef172f21f905b5523ae260f76d62, reportedly via Tornado Cash, and deployed attack contract 0x700196e226283671a3de6704ebcdb37a76658805.
    2. The attacker arranged the contract to sit behind THORChain’s Ethereum Router 0xc145990e84155416144c532e31f89b840ca8c2ce rather than acting as a simple front-end caller.
    3. The attacker invoked returnVaultAssets() with a small amount of ETH while the malicious contract was treated in the relevant path as an Asgard-vault-style destination.
    4. The Router forwarded ETH to the attacker-controlled contract path and emitted a deposit-looking event containing attacker-chosen memo data.
    5. Bifrost intercepted that event and treated it as a normal THORChain deposit instead of recognizing it as a manipulated router/vault-return flow.
    6. The memo was deliberately malformed so THORChain followed its ordinary automatic refund path.
    7. Because the source-side event had already been accepted as authentic inbound value, the refund path released real assets from vault inventory to the attacker.
    8. The attacker repeated the pattern across multiple transactions, draining the economically significant ERC-20 balances from the affected Ethereum-side vaults.
  • What the attacker needed to be true:
    • Bifrost had to treat router event shape plus memo as sufficient proof that a real deposit had occurred.
    • The Router had to expose a path where attacker-controlled contract context could still produce a deposit-looking event.
    • THORChain’s refund semantics had to release real assets on a bad memo path without independently re-establishing that the original inbound value claim was genuine.
    • The hot vaults had to hold liquid ERC-20 inventory worth stealing once the spoofed deposit crossed the bridge-authenticity boundary.
  • Technical anatomy worth remembering:
    • This was a very sharp deposit signal != locked value bridge failure. The outbound side mostly did what the protocol said to do after an invalid memo; the real lie was earlier, when source-side event handling claimed a deposit had happened.
    • THORChain’s memo system mattered because the exploit was not just fake deposit, immediate mint. The attacker used a forged inbound plus ordinary refund handling to turn spoofed intent into real asset release.
    • The cleaner healthy-side lesson is not merely router events can be spoofed; it is deposit actions should consume only the router's own custody-proving deposit artifact, while router-adjacent vault-return or upgrade rails must never keep authority to author ordinary inbound truth.
    • The incident also shows how smart-contract composability expands the bridge trust boundary: if event interpretation depends on call context, an attacker-controlled contract behind or beside the router becomes part of the bridge verifier.
    • No separate price-oracle bug or lending-market mispricing was needed. Once Bifrost accepted the fake deposit, the vault inventory itself became the payout source.

Three deposit-truth promotions this incident collapsed

  1. Some router-adjacent ETH movement and deposit-looking event existed

    • The attacker really did get the THORChain Router to forward ETH into the fake Asgard-style path, and the Router really did emit an event that looked deposit-shaped to Bifrost.
    • That only proved ETH moved somewhere through a router-adjacent helper path plus an event with deposit-like shape was emitted, not that a user had entered the canonical THORChain deposit lane with redeemable value.
  2. That helper-path artifact still counted as canonical inbound deposit truth

    • Bifrost still promoted the event into ordinary deposit semantics even though THORChain’s own postmortem describes the path as a fake-router / returnVaultAssets() construction where the Router was acting against an attacker-authored Asgard-style context rather than the canonical user-deposit path.
    • The dangerous jump was not merely that an event existed; it was that one router-adjacent maintenance-style path retained the authority to publish the same inbound truth the canonical deposit lane was supposed to own exclusively.
  3. That accepted inbound truth still deserved immediate refund-release authority

    • Once the forged inbound crossed Bifrost’s authenticity boundary, THORChain let the deliberately bad memo steer the system into its normal refund machinery and spend real ERC-20 inventory from live vault balances.
    • The same source-side lie therefore inherited ordinary refund cash-out authority before any narrower lane budget, route-local quarantine, or provenance re-check interrupted it.
  • Representative transactions and contracts:
    • Ethereum Router: 0xc145990e84155416144c532e31f89b840ca8c2ce
    • Affected vault highlighted in public writeups: 0xf56cba49337a624e94042e325ad6bc864436e370
    • Attack contract: 0x700196e226283671a3de6704ebcdb37a76658805
    • Attack EOA: 0x8c1944fac705ef172f21f905b5523ae260f76d62
    • Representative exploit transactions from THORChain’s postmortem: 0x10352e6ec052771a92f05f93e037e066873f64bb502d4488726697987f054595, 0x1c6ef4d5122f1287085097ac37df076d43f389bfc62a1bdfcd3163254b5fe94a, 0x0b39a878f1bf3daa78be149222dd8e5fa3e37b54d0451872b3d7a2cbf7f070e2, 0x01f38f17ba838b54350f8e2a2bd54fcdd9cf3c45fa1d2a735f5311507671be9e, 0xa89d90f300fed8d1d987dec86d0d628f31ffd2d8aefdd857ad90151084531d4c, 0x9db403ad39d3fe78de378af0b49f03d244326662f7fee230db87d12a624f564b
  • Response / mitigation:
    • THORChain halted Ethereum activity and later kept ETH disabled until the router and Bifrost logic could be reworked and audited.
    • The team stated that LPs would be made whole from treasury resources and recovery financing.
    • Post-incident changes emphasized stricter event handling, broader audits, a bug-bounty program, active red-team review, solvency checks, node-triggerable timeouts, and outbound throttling.

Pattern tags

Why the exploit worked

  • THORChain let two unequal source-side objects speak too similarly about ETH-side deposit truth: the canonical router deposit path and a router-adjacent returnVaultAssets() flow. Once the latter could still emit a deposit-looking artifact that Bifrost parsed as ordinary inbound value, the bridge had already split its own source-side authenticity model.
  • The decisive break was not merely bad memo caused refund. The attacker first forged the upstream fact that a normal refundable deposit had happened at all. After that, THORChain’s ordinary memo-validation and refund machinery simply spent against a fiction the bridge had already accepted.
  • The healthy-side boundary was narrower than router emitted something. The system needed router-authored event from the canonical custody-changing deposit lane, not any router-adjacent event shape that resembled deposit intent while ETH moved somewhere in the surrounding call path.
  • This is also why the incident pairs so tightly with the July 15 exploit while still preserving a distinct lesson. The first exploit let wrapper context outside the router redefine what outer tx.value meant; the second let a path behind or beside the router keep deposit-authorship authority it should have lost.
  • THORChain also lacked a meaningful containment break between one fake inbound admitted and live ERC-20 inventory released on refund. Once Bifrost promoted the counterfeit source-side fact into normal inbound accounting, the refund path could cash it out immediately.

Detection and audit pivots

  • Enumerate every router or bridge-core path that can emit deposit-looking artifacts, not just the public deposit() entrypoint. Refund helpers, vault-return flows, migrations, upgrade shims, and recovery rails should be reviewed as potential alternate authors of inbound truth.
  • For each bridge-watched event, ask whether the emitter path itself proves the same custody change ordinary deposits are supposed to prove. If a watcher would still treat the event as fresh deposit authority even when it came from a helper branch with different semantics, treat that as a live bridge-authentication bug.
  • Trace memo and refund logic backward from payout to source-side proof. The key review question is whether invalid memo -> refund can ever release assets against an inbound record whose authenticity was inherited from a weaker event surface than the canonical deposit lane.
  • Review composable router topologies adversarially: contracts in front of, behind, or called by the router can all become part of the bridge verifier if Bifrost or relayers infer deposit truth from surrounding call context rather than from one canonical custody artifact.
  • Compare accepted inbound facts with route-local release limits. If one forged router event can still command multi-asset refunds from hot-vault inventory before a narrower throttle, lane budget, or quarantine applies, the bridge is missing a second line of defense even after the source-side bug exists.

Failure-prevention checklist

  • Restrict ordinary inbound authorship to one canonical router deposit artifact. Vault-return helpers, recovery flows, upgrade shims, and returnVaultAssets()-style paths should never emit or relay the same deposit truth ordinary user deposits use unless they also satisfy the exact same custody proof.
  • Bind Bifrost to path kind as well as event shape. A deposit-looking event is not enough; relayers should know whether it came from the canonical user-deposit lane or from a helper path with different semantics.
  • Separate refund-worthiness from memo syntax alone. Before bad memo -> refund spends live vault inventory, the refund path should still be able to point to the original canonical deposit object that proved user value really arrived.
  • Treat behind-the-router contracts as part of the bridge verifier surface. If an attacker-controlled contract can influence whether the router emits a deposit-looking artifact, that contract topology needs the same adversarial review as the relayer parser itself.
  • Deauthorize special-purpose routes once they no longer need to speak with deposit authority. A vault-return or migration helper that retains ordinary inbound semantics after the intended maintenance window is already latent counterfeit-deposit surface.
  • Keep hot-vault refund authority bounded. One accepted inbound should not immediately unlock large multi-asset refunds without route-local caps, staged release, or fast halt levers.
  • Reconcile refund-triggering inbound records against canonical router custody and route provenance quickly enough to detect deposit-shaped event did not come from the canonical custody lane before hot-vault inventory is spent.

Audit prompts

  • Which exact router functions can emit artifacts Bifrost interprets as fresh inbound deposits, and which of them are supposed to represent ordinary user custody change versus maintenance or vault-return semantics?
  • When Bifrost sees a deposit-looking event, what concrete fields or call-path predicates prove that the event came from the canonical user-deposit lane rather than from returnVaultAssets() or another helper rail?
  • Can a contract behind, beside, or called by the router still cause the canonical Router to emit the same deposit-shaped event without creating the same economic state a normal deposit would create?
  • If THORChain decides a memo is invalid and initiates a refund, where is the original inbound’s custody provenance re-checked before vault assets are released?
  • Which legacy recovery, migration, or upgrade helpers still retain the authority to mint refund-worthy inbound truth, and how would operators know that those special paths remain live?
  • What route-local limits stop one forged deposit artifact from immediately draining the hot-vault ERC-20 inventory through repeated refund cycles?
  • How quickly can operators distinguish normal deposit event from canonical lane from helper-path event with deposit-like shape when Ethereum-side router traffic spikes or contracts interact compositionally?

Lessons that should already be standard

  • Router emitted a deposit-looking event is not the same thing as a user made a canonical deposit. Event shape alone is too weak when helper paths and adversarial contracts can still reach the same emitter.
  • Refund logic is not operational glue; it is spend logic. Once a fake inbound crosses the authenticity boundary, bad memo -> refund becomes a direct cash-out rail against hot-vault inventory.
  • Special-purpose maintenance flows are part of bridge authentication if relayers cannot distinguish them from ordinary deposit authors. Helpers do not stay harmless just because they were introduced for recovery or vault-management reasons.
  • Contracts behind or beside the router can be verifier-adjacent even when the bridge team thinks only the public deposit entrypoint matters. Composability widens the source-side speaker set unless the protocol narrows it explicitly.
  • Deauthorization matters as much as initial design. A route that once needed to move assets for vault-return or migration purposes should lose ordinary inbound authority as soon as that narrower job is complete.
  • Bounded refund release should already be standard. One forged inbound plus one ordinary invalid-memo path should not have had line-of-sight to the vault’s economically significant ERC-20 inventory.

Why this incident matters

  • It is one of the cleanest bridge cases where the relayer / watcher stack was not malicious; it was faithfully honoring a source-side signal whose semantics were weaker than the protocol believed.
  • It extends the usual bridge-failure lesson beyond forged proof and key compromise: source-chain event design and contract-context assumptions are themselves verifier code.
  • It preserves the sharper deposit-authorship lesson too: not every router-adjacent event that looks like a deposit should retain the right to author refund-worthy inbound truth. That authority had to stay pinned to the canonical deposit artifact and custody path.
  • It is also a memorable example of how refund logic can become the cash-out path once a fake inbound deposit crosses the authenticity boundary.
  • It also preserves the separate bounded-release lesson: one forged inbound plus one ordinary bad memo -> refund path still controlled too much immediately spendable hot-vault inventory before operators could isolate the route. For that blast-radius question, pair this incident with bridge-bounded-release-design.

Internal linkages

Control surface

  • The leverage sat in the ETH Router’s event semantics, Bifrost’s interpretation of which router paths were allowed to author deposit truth, the memo / refund state machine, and the hot-vault inventory that those signals were allowed to release.

  • The clean design boundary is worth preserving explicitly: ordinary deposits should have consumed only the router’s canonical custody-proving deposit artifact, while router-adjacent vault-return or upgrade rails should have remained narrower special-purpose paths rather than alternate authors of inbound truth.

  • The loss size also depended on containment: once the forged deposit crossed the authenticity boundary, the route could immediately convert that one bad source-side fact into real outbound inventory instead of hitting a narrower lane budget, staged release, or route-local brake first.

  • THORChain did not mainly fail because refunds are dangerous in isolation. It failed because the protocol accepted a fake deposit premise and then let perfectly ordinary refund logic spend real assets against that fiction.

  • Sources:

  • Last reviewed: 2026-08-02 UTC