Wormhole Guardian Signature Verification Bypass / Forged VAA Mint (2022-02-02)
- Name: Wormhole guardian signature verification bypass / forged VAA mint
- Date: 2022-02-02
- Protocol: Wormhole / Portal Bridge
- Chain: Solana + Ethereum
- Category: bridge verification failure / signature-verification bypass / forged-message processing / unbacked wrapped-asset mint
- Loss: about 120,000 weETH / wETH, worth roughly 326M at the time
- Summary: An attacker exploited the Solana-side Wormhole core contract’s
verify_signaturespath because Wormhole did not keepguardian-signature evidencetied tothe one runtime-authored instructions sysvarthat was supposed to certify it. Wormhole expectedinstruction_accto be the canonical Solana instructions sysvar because it uses priorsecp256k1-verification instructions in the same transaction as proof that enough Guardians signed the VAA payload. But the vulnerable release never assertedinstruction_acc.key == solana_program::sysvar::instructions::id(). That let attacker-controlled account data masquerade as runtime-authenticated instruction metadata, mark thesignature_setquorum as valid, post a forged VAA, mint 120,000 unbacked Wormhole-wrapped ETH on Solana, and then redeem 93,750 of it back into native ETH from Ethereum-side bridge custody. - Trigger / entry point:
- The Solana core contract’s
verify_signaturesfunction accepted aninstruction_accaccount from the caller. - The vulnerable code used
solana_program::sysvar::instructions::load_instruction_at(...)over the supplied account data to parse the supposed priorsecp256k1verification instruction. - That API reads bytes from the provided account but does not itself prove the account is the canonical instructions sysvar.
- Wormhole relied on the resulting
signature_setaccount to authorizepost_vaa, and Portal relied on that VAA to authorizecomplete_wrappedminting.
- The Solana core contract’s
- Root cause:
- Wormhole treated a caller-supplied account as trusted Solana runtime metadata without validating that it was the real instructions sysvar.
- On Solana, reference-only accounts are not implicitly trustworthy; programs must verify them explicitly before using them as security-critical context.
- The missing identity check collapsed the guardian-authentication boundary because attacker-crafted bytes could masquerade as a successfully verified guardian-signature instruction stream.
- More sharply: Wormhole let
sysvar-shaped account datastand in forthe canonical runtime-authored verifier context, so the verifier no longer had one protocol-owned root object for guardian-signature truth. - The bug sat in the bridge verifier itself, so downstream token minting logic faithfully executed a false authenticity claim.
- Exploit path:
- The attacker created a fake account populated with data shaped like the Solana instructions sysvar and with a forged prior
secp256k1-verification layout. - They invoked Wormhole’s
verify_signaturesinstruction and passed that fake account asinstruction_acc. - Because the program never checked that
instruction_accwas the canonical instructions sysvar,load_instruction_at(...)parsed attacker-controlled bytes as if the Solana runtime had authored them. verify_signaturesused that forged instruction metadata to mark enough entries in thesignature_setaccount astrue, satisfying Wormhole’s 2/3+ guardian-consensus rule without any real guardian signatures.- With the forged
signature_set, the attacker calledpost_vaaand created a malicious Wormhole message / VAA authorizing a mint to their own Solana address. - The attacker then called
complete_wrapped, which used Wormhole’s PDA mint authority to mint 120,000 weETH on Solana. - They bridged 93,750 of that unbacked weETH back to Ethereum and redeemed it from Portal custody as native ETH, then swapped much of the remainder into SOL and USDC on Solana.
- The attacker created a fake account populated with data shaped like the Solana instructions sysvar and with a forged prior
- What the attacker needed to be true:
- The Solana verifier had to trust user-supplied instruction-account data as if it were the genuine instructions sysvar.
- The forged
signature_sethad to satisfy Wormhole’s guardian-consensus threshold for posting a VAA. - Portal’s mint path had to accept any Wormhole-authenticated message at face value and mint wrapped assets once the verifier returned success.
- Ethereum-side custody still had to contain redeemable ETH backing legitimate wrapped ETH.
- Technical anatomy worth remembering:
- This was not a guardian key theft. The attacker forged the bridge’s proof that guardians had signed.
- The critical state transition was
fake instruction sysvar -> forged signature_set -> forged post_vaa -> legitimate complete_wrapped mint, not a direct token-contract bug. - The decisive lie was not merely
signature parser bug; it wascounterfeit verifier context became guardian truth. On this path, canonical sysvar identity was part of the signed-message security object, not auxiliary plumbing. - The missing check was tiny but decisive. Wormhole’s deployed fix added exactly this guard near the top of
verify_signatures:if *accs.instruction_acc.key != solana_program::sysvar::instructions::id() { return Err(SolitaireError::InvalidSysvar(*accs.instruction_acc.key)); }
- The official incident report also matters for process lessons: a Jan. 13, 2022 public toolchain-upgrade commit had incidentally switched Wormhole toward the checked sysvar helpers, but that upgrade had not yet been released. The exploit therefore landed in the window between public disclosure of the safer pattern and onchain deployment of the fix.
- Wormhole had to ship two containment layers after the core verifier fix: first patch
verify_signatures, then separately blacklist already-prepared fraudulent VAAs the attacker had generated before the patch landed. - The exploit created unbacked wrapped ETH on Solana first, then converted verifier failure into Ethereum custody theft by redeeming those counterfeit wrapped assets through the normal bridge path.
Three bridge-truth promotions this incident collapsed
- A verifier-shaped guardian-signature context existed at all
- The transaction carried an
instruction_accaccount and Wormhole could parse bytes from it with Solana’s instruction-introspection helpers. - At this stage the strongest true fact was only
some sysvar-shaped account data exists and can be parsed, notthe Solana runtime authenticated guardian-signature verification for this VAA.
- The transaction carried an
- That parsed context was promoted into canonical truth that this exact guardian quorum had signed this exact VAA
- This was the decisive failure. Because
verify_signaturesnever provedinstruction_accwas the canonical instructions sysvar, attacker-authored bytes were allowed to stand in for runtime-authenticatedsecp256k1verification history. - The bridge therefore collapsed
instruction-looking context is presentandthe runtime proved enough Guardians signed this messageinto the same verifier meaning, letting a forgedsignature_setbecome accepted VAA truth.
- This was the decisive failure. Because
- That accepted bridge truth still deserved immediate mint and redemption authority
- Once the forged
signature_setwas accepted, downstreampost_vaaandcomplete_wrappedlogic still treated the counterfeit VAA as ordinary mint authority for120,000weETH on Solana. - The route then preserved almost no blast-radius separation between
one verifier result liedandlive Ethereum custody can now be redeemed against that lie, which is why93,750weETH could be cashed out before operators fully contained the path.
- Once the forged
- Representative transactions and contracts:
- Solana Wormhole core program:
worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth - Malicious
verify_signaturestransaction cited by CertiK:25Zu1L2Q9uk998d5GMnX43t9u9eVBKvbVtgHndkc2GmUFed8Pu73LGW6hiDsmGXHykKUTLkvUdh4yXPdL3Jo4wVS - Malicious
post_vaatransaction cited by CertiK:2SohoVoPDSdzgsGCgKQPByKQkLAXHrYmvtE7EEqwKi3qUBTGDDJ7DcfYS7YJC2f8xwKVVa6SFUpH5MZ5xcyn1BCK - Fraudulent 120,000 weETH mint transaction on Solana:
2zCz2GgSoSS68eNJENWrYB48dMM1zmH8SZkgYneVDv2G4gRsVfwu5rNXtK5BKFxn7fSqX9BvrBc1rdPAeBEcD6Es - Ethereum redemption transactions highlighted by Wormhole:
0x4d5201dd4a377f20e61fb8f42e6f929ec16bcec918f0584e39241d15b254a80f,0xd31b155e259a403ebe69831fae0ec2b4bd33dfa090c43b605a57d5c72c4fbbc7,0xacd309b02e4b533484d148de9ab0adf367ed4e70ed751d1ff036152dc3bc0479 - Solana-side emergency verifier-fix governance transaction:
2G8nVB9MEhfmmF4BEE3AWAVWgSDnbevv5iJ69XymtA4wfgp7FugAx1UuajTBQzfwFNwyQjFffUJyPx1bymRweE1H - Solana-side follow-on blacklist / safeguard upgrade transaction:
5q8A9MjUXjRNxS3RTqRsFJs2ka4MAiYiACQvPdPk35Li7VCg1fA8gAz5ReohAbvDy6PUyf6brWLivDK2QX9VK6u2 - Patch commit adding the missing sysvar-account check:
e8b91810a9bb35c3c139f86b4d0795432d647305 - Earlier public toolchain-upgrade commit that incidentally moved toward checked sysvar helpers:
7edbbd3677ee6ca681be8722a607bc576a3912c8
- Solana Wormhole core program:
- Response / mitigation:
- Wormhole contributors coordinated with Guardians to stop relaying messages, effectively pausing bridge activity while the incident was contained.
- The team developed and deployed a Solana-side contract fix that explicitly checked the instructions sysvar account before accepting signature-verification results.
- Because the attacker had already prepared additional fraudulent messages before that fix landed, Wormhole later deployed extra Solana-side Portal safeguards to blacklist those specific malicious VAAs.
- Jump Crypto recapitalized the Ethereum-side contract with 120,000 ETH so all Wormhole-wrapped ETH would remain fully backed when the network restarted.
- Wormhole publicized a $10M whitehat / recovery offer and later reopened the network after patching and recapitalization.
- Key transaction hashes:
- Malicious
verify_signaturestransaction:25Zu1L2Q9uk998d5GMnX43t9u9eVBKvbVtgHndkc2GmUFed8Pu73LGW6hiDsmGXHykKUTLkvUdh4yXPdL3Jo4wVS - Malicious
post_vaatransaction:2SohoVoPDSdzgsGCgKQPByKQkLAXHrYmvtE7EEqwKi3qUBTGDDJ7DcfYS7YJC2f8xwKVVa6SFUpH5MZ5xcyn1BCK - Fraudulent 120,000 weETH mint transaction on Solana:
2zCz2GgSoSS68eNJENWrYB48dMM1zmH8SZkgYneVDv2G4gRsVfwu5rNXtK5BKFxn7fSqX9BvrBc1rdPAeBEcD6Es - Ethereum redemption transactions:
0x4d5201dd4a377f20e61fb8f42e6f929ec16bcec918f0584e39241d15b254a80f,0xd31b155e259a403ebe69831fae0ec2b4bd33dfa090c43b605a57d5c72c4fbbc7,0xacd309b02e4b533484d148de9ab0adf367ed4e70ed751d1ff036152dc3bc0479 - Emergency verifier-fix governance transaction:
2G8nVB9MEhfmmF4BEE3AWAVWgSDnbevv5iJ69XymtA4wfgp7FugAx1UuajTBQzfwFNwyQjFffUJyPx1bymRweE1H - Follow-on blacklist / safeguard upgrade transaction:
5q8A9MjUXjRNxS3RTqRsFJs2ka4MAiYiACQvPdPk35Li7VCg1fA8gAz5ReohAbvDy6PUyf6brWLivDK2QX9VK6u2
- Malicious
Pattern tags
- bridge-verification-failure
- Caller-supplied
instruction_accdata was allowed to impersonate the canonical Solana instructions sysvar, so verifier context identity itself stopped being protocol-owned truth verify_signaturesproduced a forgedsignature_set, and the rest of Wormhole faithfully treated that counterfeit verifier output as guardian consensus rather than re-proving it downstream- One false Solana-side guardian-authentication result still had immediate line-of-sight to
complete_wrappedmint authority on Solana and then to live ETH redemption against Ethereum-side Portal custody - The Jan. 13 checked-helper commit versus Feb. 2 onchain fix gap preserved a painful operational lesson: once a safer verifier-boundary pattern is public, undeployed high-value routes are already living inside a patch-lag risk window
Why the exploit worked
- Wormhole’s verifier accepted
sysvar-shaped bytesinstead of proving that the bytes came from the one runtime-authored instructions sysvar account. On Solana that identity check is not cosmetic plumbing; it is the thing that says priorsecp256k1verification instructions were actually emitted by the runtime and not authored by the caller. - The bridge’s real security object on Solana was not just
guardian signatures exist, butthe canonical instructions sysvar proves guardian signatures were verified for this VAA. Onceinstruction_acccould be substituted, the attacker did not need guardian keys; they only needed to counterfeit the verifier context Wormhole trusted to mint guardian truth. - Wormhole then faithfully amplified that forged result across the rest of the bridge.
verify_signatureswrote asignature_set,post_vaaaccepted it as quorum evidence, andcomplete_wrappedtreated the posted VAA as sufficient mint authority. No later stage re-opened the authenticity question because the verifier had already answered it. - The economic loss came from bridge architecture, not just a local Solana parsing bug. The same false authenticity result that minted 120,000 unbacked weETH on Solana could still be redeemed back into native ETH from Ethereum-side Portal custody before operators contained the route.
- Operationally, Wormhole’s own incident report makes the patch-lag lesson explicit: the safer checked-sysvar helper path had already become public through the toolchain-upgrade commit, but production had not yet rolled it out. For high-value bridge verifiers,
known-better but not yet deployedis already part of the live risk surface.
Detection and audit pivots
- Treat every caller-supplied account that claims to be runtime metadata, a sysvar, or another verifier-side root object as hostile until the program proves its canonical address and derivation. On Solana,
looks like the instructions sysvaris not a security property. - Trace the full verifier-output chain, not just the local bug. A healthy review should ask
what downstream state becomes authoritative if this verifier returns one false success?In Wormhole the answer was immediatelysignature_set -> post_vaa -> wrapped-asset mint -> Ethereum custody redemption. - Diff public commits, dependency upgrades, and helper migrations for newly introduced checked-API boundaries, then compare them against what is actually deployed. If the repository already contains a safer verification invariant than mainnet, the route is living with an observable patch-lag window on custody code.
- Ask whether the protocol keeps one machine-checkable root object for signer / guardian truth or reconstructs that truth from caller-provided context plus parsing assumptions. If the latter, counterfeit context may be enough to forge consensus without compromising any signer key.
- Model blast radius assuming the verifier lies once. If one forged VAA can still mint a route-scale wrapped asset and redeem it against deep destination custody before throttles fire, bounded-release controls are underdeveloped even if the verifier is usually correct.
Failure-prevention checklist
- Prove canonical sysvar identity before parsing any runtime-authored context. If guardian-signature truth depends on the instructions sysvar, the verifier should fail before any parsing or hash comparison unless
instruction_acc.key == solana_program::sysvar::instructions::id(). - Keep one fused guardian-authentication object from signature check through mint authority.
verify_signatures,signature_set,post_vaa, and downstream mint paths should preserve one machine-checkable story forthese exact Guardians authorized this exact VAA, not reconstruct trust from caller-chosen context at each step. - Treat checked-helper migrations and dependency upgrades as live security work, not routine refactors. If a newer helper proves the canonical sysvar boundary that production does not yet enforce, undeployed routes are already carrying patch-lag risk on custody code.
- Bound release even when the verifier is usually correct. One forged VAA should not have immediate line-of-sight to route-scale minting and deep destination-side redemption before operators can narrow the lane.
- Add route-local emergency controls that can freeze already-prepared fraudulent messages, not just future verifier calls. Wormhole’s own response needed both the verifier fix and a later blacklist for forged VAAs already in flight.
- Reconcile wrapped supply, posted VAAs, and destination-side custody continuously enough to detect
counterfeit wrapped asset existsbefore most of it can be redeemed against canonical reserves. - Regression-test fake-runtime-context cases directly: forged instructions sysvar account, malformed prior
secp256k1instruction stream, forgedsignature_setprogression, and end-to-endfake verifier output -> mint -> redeemsimulations. - Budget route exposure so a single verifier-success event cannot drain the whole reserve surface. If one Solana-side authenticity lie can immediately reach Ethereum custody, the bridge has not separated verification risk from balance-sheet risk.
Audit prompts
- Which exact account or object is the verifier trusting as runtime-authored context, and where is its canonical identity asserted before any parser reads bytes from it?
- If
verify_signaturesreturns one false success, what exact downstream objects become authoritative next:signature_set,post_vaa, mint authority, redeemability, or governance side effects? Which of those stages ever re-open the authenticity question? - Can caller-controlled accounts, PDAs, or instruction-order assumptions impersonate any part of the guardian-verification boundary even if signature parsing itself is locally correct?
- Does the route have a public patch-lag window right now where repository code, helper migrations, or dependency updates already preserve a stronger verifier invariant than the deployed program?
- What concrete controls stop one forged VAA from reaching route-scale wrapped-asset minting or destination-side reserve redemption before a pause lands?
- Can responders invalidate already-prepared fraudulent messages after fixing the root verifier bug, or does the route assume
patch deployedautomatically meansall forged artifacts are dead? - Which monitors compare wrapped supply, custody backing, and unusual verifier-success / post-
VAAactivity quickly enough to matter during a live exploit? - Does the route treat Solana runtime metadata, instruction introspection, and other reference-only accounts as custody-critical inputs during review, or are they still being audited like peripheral plumbing?
Lessons that should already be standard
- On Solana, account identity is security logic. A parser that reads from the wrong account is not doing a weaker version of verification; it is often verifying nothing.
- Runtime context is part of the signed-message security object. If a bridge depends on the instructions sysvar to prove that guardian signatures were checked, then
which account supplied that contextis as important as the signature math itself. - Patch-lag on custody code is a live attack surface. Once a safer verifier boundary exists in public source or dependency history, attackers may have both a bug hint and a deadline.
- One verifier lie should not equal immediate reserve loss. Wormhole shows that bridges need bounded-release design in addition to correct verification, because counterfeit wrapped assets can become real destination-side losses very quickly.
- Fixing the root bug may still leave forged artifacts alive. Teams need a second response playbook for already-prepared messages, queued releases, or other exploit residue that remains executable after the primary patch lands.
No guardian key was compromisedis not a comforting postmortem fact if the verifier could mint guardian truth locally. Contract-side authenticity failures are custody failures.
Why this incident matters
- It is one of the clearest examples of a bridge losing custody because its verifier accepted forged authenticity, not because its validator keys were stolen.
- It shows how wrapped-asset solvency depends entirely on the correctness of the destination-side verifier. Once that verifier lies,
wrapped assetbecomescounterfeit IOUinstantly. - It is also a durable Solana-specific lesson: untrusted account substitution is not a niche footgun when programs rely on sysvars, PDAs, and cross-instruction introspection for security-critical logic.
- More broadly, it preserves a reusable design rule for the corpus: runtime metadata identity is part of the verifier root-of-truth object. If a bridge accepts
sysvar-shaped bytesor other caller-authored verifier context instead of the one canonical runtime-authored object, guardian signatures can be forged without touching a guardian key. - It is also a strong bounded-release case study: one forged guardian-authentication result was enough to mint
120,000counterfeit Solana-side wrapped ETH and redeem93,750of it against live Ethereum custody before operators could freeze the route, showing how little separation existed betweenfalse bridge truth acceptedandnine-figure custody loss.
Internal linkages
- Core recurring pattern: bridge-verification-failure.
- Positive-design companion: bridge-truth-security-object — useful when the sharper question is what one canonical guardian-authenticated object
verify_signaturesandpost_vaashould have bound before any mint or redemption path honored it. - Positive-design companion: root-object-authenticity-and-trust-anchor-recomputation-discipline — useful when the sharper question is what exact Solana runtime-authored root object Wormhole should have recomputed or pinned before any caller-supplied account data was allowed to define guardian-verification reality.
- Positive-design companion: bridge-bounded-release-design — useful when the sharper question is why one forged VAA path was still allowed to mint
120,000weETH and redeem most of it against live Ethereum custody before operators could react. - Adjacent root-object seam: account-confusion-root-of-trust-substitution — Wormhole is also a clean
fake trusted sysvarcase, where the verifier first accepted the wrong root account before bridge-specific message authenticity collapsed. - Adjacent verifier-path contrast: proof-to-message-binding-failure — Hyperbridge and BNB Chain kept a real trusted root but detached it from the claimed message, whereas Wormhole failed one step earlier by letting attacker-controlled Solana account data forge the guardian-verification result itself.
- Useful contrast: signer-quorum-compromise — Wormhole produced the same practical outcome as a stolen guardian quorum, but the important lesson is that no guardian keys were actually compromised; the verifier forged consensus on their behalf.
Control surface
-
The leverage sat in Solana-side guardian-signature verification, the identity of the
instruction_accruntime-metadata account,signature_setcreation, VAA posting, and Portal’s wrapped-token mint authority. -
Wormhole did not primarily fail because Ethereum custody logic was weak. It failed because Solana-side verification incorrectly minted authenticity, and the rest of the bridge honored that forged result.
-
The sharp preserved boundary is that verifier context identity was itself custody code: once Wormhole let a caller choose the account that defined
signature verification already happened, the bridge had already ceded guardian truth before any wrapped-asset logic ran. -
Sources:
- https://wormholecrypto.medium.com/wormhole-incident-report-02-02-22-ad9b8f21eec6
- https://kudelskisecurity.com/research/quick-analysis-of-the-wormhole-attack
- https://www.certik.com/blog/wormhole-bridge-exploit-incident-analysis
- https://www.chainalysis.com/blog/wormhole-hack-february-2022/
- https://github.com/wormhole-foundation/wormhole/commit/e8b91810a9bb35c3c139f86b4d0795432d647305
- https://github.com/wormhole-foundation/wormhole/commit/7edbbd3677ee6ca681be8722a607bc576a3912c8
-
Last reviewed: 2026-08-01 UTC