Poly Network (2021)

A $611M cross-chain bridge exploit — at the time the largest DeFi loss ever. Notable both for its size and its resolution: the attacker eventually returned essentially all the funds, claiming the attack was educational rather than malicious.

Timeline

  • August 10, 2021: Attacker drained $611M across three chains (Ethereum, Binance Smart Chain, Polygon). Theoretical loss higher because USDT on Ethereum was frozen by Tether before withdrawal.
  • August 11–25, 2021: Attacker began returning funds. Communicated via on-chain messages, said "it's always the plan" to return funds.
  • August 25, 2021: All recoverable funds returned. Poly Network published a postmortem.

Root Cause

Poly Network's cross-chain bridge included a EthCrossChainManager contract on Ethereum that could execute arbitrary cross-chain messages. The keeper-validator set was supposed to verify each message's origin. But:

  1. The contract had a privileged function putCurEpochConPubKeyBytes that updated the validator set ("keeper public keys").
  2. This function had a modifier onlyOwner — which referenced EthCrossChainData.owner, a contract the manager called via the same generic message-execution machinery.
  3. Because the manager itself was the owner of EthCrossChainData, and the manager would execute any message it could verify, the attacker constructed a message whose effect was to make the manager call putCurEpochConPubKeyBytes with the attacker's chosen keeper set.

The message verification failed to distinguish "messages that touch governance state" from "messages that move user funds." Once the attacker controlled the keeper set, they could approve any subsequent message, including arbitrary withdrawals.

Exploit Path

1. Attacker crafts a message that, when executed by the manager,
   calls putCurEpochConPubKeyBytes([attacker_keeper]).
2. Attacker submits the message with a signature.
3. The signature was crafted such that the on-chain verification
   (which compared against the current keeper set) passed — possible
   because the attacker had figured out a way to forge it with respect
   to the existing keepers, or possibly via the keeper-set update path
   being entirely callable from message execution.
4. Manager executes the message, updating EthCrossChainData's keeper set
   to attacker-controlled keys.
5. Attacker submits a withdrawal message; verification now uses attacker
   keepers; passes; funds withdrawn.
6. Repeat across three chains.

The exact mechanics of the initial signature forgery are debated; the postmortem and subsequent analyses point to a combination of weak keeper update access control and a deeper signature-verification anomaly. The net effect is unambiguous: attacker took over the validator set, then withdrew.

What an Audit Should Have Caught

  1. Privileged-function reachability. putCurEpochConPubKeyBytes was callable through the same generic message-execution path that the bridge used for any other action. Privileged operations should require separate authentication, not be embedded in the data-plane verification.

  2. onlyOwner semantics relative to attack surface. The manager being the owner of the data contract meant any message the manager could execute could change governance. The onlyOwner check was technically present but did not provide meaningful protection.

  3. Validator-set updates should be timelocked. Even if the validator set is updateable on-chain, the update should be observable for a delay window (hours-to-days), giving the team and the community time to react to a malicious update.

  4. Generic message execution is dangerous. A bridge that can execute "any function on any contract" has the largest possible attack surface. A more constrained bridge (only token transfers, only specific function selectors) would have prevented this class of attack entirely.

Lessons

  1. Separate data-plane and control-plane authentication. Routine messages (user withdrawals) and governance messages (validator-set updates) should not share an authentication mechanism. The bug here was treating them identically.

  2. Validator-set updates need extra protection. Multi-step process, timelock, ideally external verification.

  3. Generic cross-chain execution is high-risk. "We can call anything on the destination chain" sounds flexible; it's the most exploit-friendly possible design. Constrain to specific safe operations.

  4. Recovery is exceptional, not expected. Poly Network was extraordinarily lucky — the attacker chose to return funds. No subsequent major bridge exploit has had the same outcome. Audits cannot rely on attacker benevolence.

  5. Tether's freeze ability mattered. USDT on Ethereum was frozen by Tether shortly after the exploit, preventing further loss. Centralized stablecoin features cut both ways: they're a centralization risk in normal operation, and an emergency lever in incidents.

The Poly Network exploit predates the Wormhole, Ronin, and Nomad attacks. Each of those incidents involved different specific bugs, but the meta-pattern — bridges as the highest-value, lowest-defended layer in DeFi — was already visible in 2021.