Wormhole Bridge Hack: $326M Exploit Technical Analysis

Article author

Wormhole Bridge Hack: $326M Exploit Technical Analysis

On February 2, 2022, the Wormhole token bridge lost 120,000 wETH — approximately $326 million at the time — in what remains one of the largest smart contract exploits in DeFi history. The attack did not require stolen keys, social engineering, or majority control of the Guardian validator network. It required one thing: a deprecated Solana program API that failed to verify which account it was reading from.

Understanding this exploit is essential for every team building on Solana, every protocol that relies on cross-chain messaging, and every auditor reviewing Solana programs. The root cause was a smart contract verification flaw in the Wormhole Solana bridge program — not a key compromise, not a Guardian network failure. The Guardian keys were never touched. The bridge’s own code handed the attacker authorization it should never have granted.

What was the primary technical vulnerability in the Wormhole hack?

The vulnerability lived in the verify_signatures instruction of Wormhole’s Solana bridge program (bridge.so). This function was responsible for verifying that a SignatureSet account — containing Ed25519 or Secp256k1 signatures from Guardian nodes — represented genuine consensus before authorizing a Verifiable Action Approval (VAA).

The flaw: verify_signatures used the deprecated solana_program::sysvar::instructions::load_instruction_at function to check that a Secp256k1 pre-verification instruction had been called earlier in the same transaction. The deprecated variant does not validate that the account passed to it is actually the Solana instructions sysvar (Sysvar1nstructions1111111111111111111111111). It reads from whatever account sits at the named index — including an account entirely controlled by the caller.

An attacker can therefore pass a fabricated account that mimics the layout of the instructions sysvar, pre-populated with attacker-controlled signature data over an attacker-chosen payload. The function reads the fake data, finds the Secp256k1 call “present” (in a completely different context), marks the VAA as Guardian-approved, and returns success.

With a fraudulently approved VAA in hand, the attacker invoked complete_wrapped, which trusts the bridge program’s VAA approval to authorize minting of wrapped assets on Solana. The result: 120,000 wETH minted without any corresponding ETH locked on Ethereum.

A fix — replacing load_instruction_at with load_instruction_at_checked, which enforces that the account is actually the instructions sysvar — had been committed to the Wormhole GitHub repository before the exploit occurred but had not yet been deployed to mainnet.

Factor Description Impact
Deprecated sysvar API load_instruction_at without _checked variant; no owner verification on the account passed at the named index Attacker can supply a forged instruction account in place of the real instructions sysvar
verify_signatures bypass Function accepted attacker-crafted SignatureSet as proof of Guardian consensus without validating account provenance Mint authorization granted without any real Guardian signatures
Missing account owner check SignatureSet account not validated to be owned by the instructions sysvar program (Sysvar1nstructions11...) This missing check is the entire foundation of the exploit
Wrapped asset minting authority Solana bridge program held unrestricted mint authority over wrapped tokens; authorization required only a VAA marked as approved 120,000 wETH minted on Solana with no ETH locked on Ethereum; ~$326M in value at time of attack

How did the Wormhole hack exploit differ from other bridge attacks like Ronin?

The Ronin bridge hack (March 2022, ~$625M) is frequently paired with Wormhole in discussions of bridge security failures. They are fundamentally different failure modes.

Wormhole was a smart contract verification bug in the Solana bridge program. The Guardian network — a 19-node threshold signature scheme — was never compromised. The attacker bypassed it entirely by exploiting the fact that verify_signatures never checked which account it was reading from. The Guardian keys were intact, the network was operational, and it was all irrelevant: the code never consulted the real Guardian consensus.

Ronin was operational key theft. Sky Mavis operated five of Ronin’s nine validator nodes. In November 2021, Axie DAO temporarily delegated signing authority to Sky Mavis to handle transaction load. The delegation was never revoked when it expired. An attacker — later attributed to the Lazarus Group — compromised Sky Mavis internal systems and gained access to four Sky Mavis validator keys. Using the still-active Axie DAO delegation, they acquired the fifth signature via Sky Mavis’s gas-free RPC node. With five of nine valid signatures, they submitted legitimate withdrawal messages to the Ronin bridge contract. No smart contract bug was exploited. The bridge did exactly what it was designed to do when presented with five genuine validator signatures — it authorized the withdrawals.

Wormhole (Feb 2022) Ronin (Mar 2022)
Attack vector Solana program account verification bypass Social engineering and credential compromise of Sky Mavis nodes
Exploit method Forged SignatureSet account via deprecated sysvar API Legitimate signed withdrawals from stolen validator keys
Guardian / validator network Fully intact; bypassed by the code, not by the attacker Compromised — attacker held 5 of 9 validator keys
Impact method Unauthorized mint on Solana without ETH locked on Ethereum Direct withdrawal from Ronin bridge contract via valid signatures
Amount stolen ~$326M (120,000 wETH) ~$625M (173,600 ETH + 25.5M USDC)
Security insight Account-ownership validation is non-negotiable in Solana programs; threshold signatures only work if the bridge actually reads them Threshold signature schemes provide no defence against majority key compromise; delegation revocation must be enforced

Step-by-step: how the Wormhole exploit executed

  1. Account spoofing. The attacker created a Solana account mimicking the layout expected at the SignatureSet position in the Wormhole bridge program’s instruction data. This account contained attacker-controlled signatures — valid Ed25519/Secp256k1 signatures, but over an attacker-chosen VAA payload authorizing a mint of 120,000 wETH to the attacker’s Solana address.

  2. Bypass via deprecated sysvar API. The attacker submitted a transaction calling verify_signatures on Wormhole’s Solana bridge program. The program invoked load_instruction_at — the deprecated, unchecked variant — to confirm that a Secp256k1 instruction had been called earlier in the same transaction. load_instruction_at reads from whatever account is at the named index without validating that the account is the real instructions sysvar (Sysvar1nstructions1111111111111111111111111).

  3. Forged proof accepted. verify_signatures walked the signatures stored in the attacker-controlled account, found them cryptographically valid (the attacker had signed them himself, over his own payload), and marked the VAA as Guardian-approved. The Guardian network was never consulted.

  4. Minting authorized. The attacker invoked complete_wrapped with the now-approved VAA. The bridge program, trusting the VAA approval status, minted 120,000 wETH on Solana to the attacker’s address.

  5. Cross-chain extraction. The attacker bridged the minted wETH back to Ethereum through Wormhole’s legitimate cross-chain flow — the wETH existed in the attacker’s Solana wallet, so the bridge processed the withdrawal as a normal transfer. The $326M in unbacked wETH landed on Ethereum, where the attacker converted to ETH and stablecoins and exited. Jump Crypto, Wormhole’s parent company, replenished the stolen 120,000 ETH from its own reserves to make bridge users whole.

Most critical technical lessons for Solana programs and cross-chain bridges

1. Every AccountInfo passed to a Solana program is attacker-controlled until proven otherwise.

This is the foundational rule of Solana program security. A program must validate the owner, key, and — where applicable — executable and is_signer fields of every account it receives. The deprecated load_instruction_at function accepted any account placed at the named index. The modern replacement, load_instruction_at_checked, enforces that the account is actually the instructions sysvar before reading from it. Soken’s Solana audit methodology flags any use of non-_checked sysvar APIs as a Critical finding, regardless of context.

2. Privilege separation between signature verification and asset minting.

A bridge’s minting authority must sit behind a verification module that re-derives proof from canonical, program-owned state — not from caller-supplied accounts. When verify_signatures accepted an attacker-controlled account as its source of truth, the separation between “has the network approved this?” and “can we mint?” collapsed entirely. The mint instruction should derive authorization from state the program itself wrote after verifying real Guardian input.

3. VAA replay protection must be enforced on-chain.

Even if the SignatureSet had been authentic, complete_wrapped should reject VAAs whose hash has already been consumed. Wormhole added replay protection in subsequent versions, but its absence in the exploited version meant that a fraudulently approved VAA could have been reused repeatedly. Every bridge action should be gated on a consumed-VAA mapping (processed_vaas: mapping[bytes32, bool]) updated atomically at the start of execution.

4. Deprecated API usage is a Critical audit finding.

Wormhole’s vulnerability was a known deprecation. The Solana SDK had flagged load_instruction_at as deprecated and provided the _checked replacement before the exploit. A missing migration from a deprecated API is not a code-quality concern — it is a security-critical gap that attackers actively hunt for by reading changelogs and comparing undeployed commits against deployed bytecode. Solana program audits must sweep solana_program::sysvar::instructions::* for non-_checked variants and gate-fail on any match. This is standard practice in post-2022 Solana audits across Ottersec, Halborn, and Soken engagements.

5. Undeployed security fixes are public attack maps.

The load_instruction_at_checked fix had been committed to the Wormhole public repository before the exploit occurred. A sophisticated attacker who monitors target protocol repositories for security-relevant commits — particularly those swapping deprecated APIs for their checked equivalents — can reconstruct the vulnerability from the diff alone. Deployment pipelines for security-critical programs must treat the gap between “merged to main” and “deployed to mainnet” as an active exposure window. Emergency deployment procedures should close that window in hours, not days.

6. Threshold multisig does not compensate for account validation failures.

Wormhole’s Guardian network comprised 19 independent nodes running a threshold signature scheme. It was robust. It was completely irrelevant to this attack. The exploit routed around the entire consensus layer by manipulating which account verify_signatures read from. Threshold signatures protect against Guardian key compromise; they provide zero protection against a bug that never asks the Guardians for input. Defense-in-depth requires that each layer of the security model actually be invoked — a bypassed control is no control at all.

What this means for bridge audits and Solana program security

The Wormhole exploit demonstrates that cross-chain bridge security is a multi-layer problem. The Guardian network can be cryptographically sound, the economic incentives correctly aligned, and the protocol architecture well-designed — and a single deprecated function call in the on-chain program can render all of it moot.

For teams building on Solana, the account validation lesson generalizes: treat every parameter passed to your program as hostile input. Validate owner, key, discriminator, and data length before operating on any account. Use the anchor framework’s Account<T> wrapper or equivalent to enforce these checks at the type level rather than relying on manual assertion.

For bridge architects, the lesson is privilege separation and canonical state anchoring. Minting authority must trace back to program-owned state that the program itself validated — not to caller-supplied proofs that the program accepted without verification.

Soken audits every Solana program for deprecated sysvar API usage, missing account owner checks, and VAA replay protection gaps as Critical-priority items. The Wormhole pattern — bypassing a multisig threshold by manipulating the account a verification function reads from — is now a named attack class in our Solana audit methodology. If your protocol uses cross-chain messaging or wrapped asset minting, contact us at soken.dev/services-it.html to discuss a security review before deployment.

Article author

Frequently Asked Questions

What was the primary cause of the Wormhole bridge hack?

A deprecated Solana program API (`load_instruction_at` without `_checked`) in the `verify_signatures` function did not validate that the account it read from was the real instructions sysvar. The attacker passed a fabricated account with self-signed signatures, the function accepted it as Guardian consensus, and the bridge minted 120,000 wETH on Solana without any corresponding lock on Ethereum.

Were Wormhole Guardian validator keys compromised?

No. The Guardian network's 19-node threshold signature scheme was never breached. The exploit routed around it entirely by manipulating which account `verify_signatures` read its data from — the contract never actually consulted the Guardians.

How did the Wormhole hack differ from the Ronin bridge hack?

Wormhole was a smart contract verification bug on Solana — no keys stolen. Ronin was operational key theft — attackers obtained five of nine Sky Mavis validator keys via social engineering plus an unrevoked Axie DAO delegation, then submitted legitimate signed withdrawal messages.

How can Solana programs prevent this class of attack?

Validate every AccountInfo parameter: assert owner, key, and where applicable executable flags before operating on the account. Use load_instruction_at_checked (or the Anchor Account wrapper) which enforces sysvar ownership at the type level. Treat any non-_checked sysvar API call as a Critical audit finding.

What audit practices catch this issue today?

Modern Solana program audits sweep solana_program::sysvar::instructions::* usage for non-_checked variants and gate-fail on any match. Audits also verify VAA replay protection, explicit privilege separation between proof verification and mint authorization, and prompt deployment of security commits.

Chat