Summary
The Parity multisig wallet, a popular way to hold Ethereum securely with multiple signers, suffered two disasters from the same design flaw in 2017. In July, an attacker exploited it to steal about $30 million. Then in November, a curious user poking at the code accidentally triggered the flaw in reverse and permanently froze about $150 million belonging to hundreds of wallets, locking it away forever with no way to recover it. Together they are the textbook lesson in smart-contract initialization, the danger of shared library code, and why an irreversible system can punish a single missing access check twice over.
How it happened
Parity's design was clever and, it turned out, fragile. Each user's wallet was a thin smart contract holding no logic of its own. To save gas, it used delegatecall to forward any call it did not recognise to a single shared WalletLibrary contract, which then executed in the calling wallet's storage context. The flaw was that the library's initWallet function, which sets the wallet's owners, was public and had no guard to stop it being called more than once.
That one omission caused both disasters. On 19 July 2017, an attacker called initWallet on several already-deployed wallets, overwrote their owner list with just their own address, set the required signatures to one, and called execute() to drain them, making off with 153,037 ETH, about $30 million, from token-sale wallets including aeternity, Swarm City, and Edgeless. (A community "White Hat Group" used the very same exploit defensively to rescue another ~377,000 ETH from still-vulnerable wallets and later returned it.) The hurried fix protected the individual wallet contracts but left the shared WalletLibrary itself sitting un-initialized, a gap a GitHub user had flagged weeks earlier that went unaddressed. So on 6 November 2017, a user called devops199, exploring the code, called the unprotected initWallet directly on the shared library, became its owner, and then called the library's kill() function, which ran selfdestruct and deleted the shared code. Every wallet that depended on it through delegatecall was instantly bricked: 513,774 ETH, more than $150 million across 587 wallets (including around $90 million of Polkadot's own ICO funds), frozen permanently. The library was the load-bearing wall, and someone had deleted it.
Why Parity still matters
Parity is the initialization-and-shared-code lesson, taught twice. An uninitialized, publicly callable initializer let anyone claim ownership (the July theft), and treating a delegatecall library as outside the trust boundary let someone destroy it (the November freeze). On an irreversible ledger, neither could be undone, and the frozen funds are gone to this day; a community vote on a recovery proposal (EIP-999) failed in April 2018, with roughly 55% against, on immutability grounds. The defences are now standard practice in smart contract development: protect every initializer with an "already initialized" guard such as OpenZeppelin's Initializable; treat any library reached via delegatecall as inside your trust boundary and deploy it initialized and locked; never use delegatecall as a catch-all fallback; gate selfdestruct and ownership changes behind explicit access control, or remove selfdestruct entirely (Ethereum has since deprecated it, partly because of this); and initialize a singleton implementation the moment it is deployed so no one else can claim it. The multisig was meant to add safety, and a library bug erased it.
How to fix it
- There is no recovery for the frozen funds; the November freeze is permanent, which is itself the lesson of an unfixable bug on an immutable ledger.
- For the theft, the only responses were to fork or rebuild; protect every initializer and lock deployed library and implementation contracts immediately so the pattern cannot recur.
- Audit all delegatecall and proxy relationships for uninitialized implementations and publicly callable initializers before deploying.
How to avoid it
- Protect every initializer with an initialized guard or OpenZeppelin Initializable; never leave init() publicly re-callable.
- Treat any library reached via delegatecall as part of your trust boundary; deploy it initialized and locked.
- Do not use delegatecall as a catch-all fallback; explicitly allowlist which library functions are externally reachable.
- Gate selfdestruct and ownership-changing paths behind explicit access control, and prefer removing selfdestruct entirely.
- After deploying a singleton implementation, call its initializer immediately so no one else can claim it.
References
- https://www.openzeppelin.com/news/on-the-parity-wallet-multisig-hack-405a8c12e8f7
- https://medium.com/paritytech/a-postmortem-on-the-parity-multi-sig-library-self-destruct-63daca3a4cf7
- https://www.openzeppelin.com/news/parity-wallet-hack-reloaded
- https://medium.com/parity-hack-trace/parity-hack-and-153-037-stolen-eth-2a7704f59f3b
Related vulnerabilities
All Web3 →- CRITICALWEB3-HEDGEY-2024
On April 19, 2024, Hedgey Finance was drained of about $44.7 million (notional) across Arbitrum (~$42.6 million, mostly BONUS tokens) and Ethereum (~$2.1 million in USDC, ETH and other tokens). The root cause was an unvalidated attacker-controlled address combined with a stale token allowance in the ClaimCampaigns contract. createLockedCampaign granted an ERC-20 allowance via SafeERC20.safeIncreaseAllowance(IERC20(campaign.token), claimLockup.tokenLocker, campaign.amount) without validating that the caller-supplied tokenLocker was a legitimate Hedgey vesting contract, so the attacker passed their own address and obtained spend approval. cancelCampaign then refunded the deposited tokens but never called safeDecreaseAllowance, leaving the dangling allowance live after capital was returned. Funding the deposit with a Balancer flash loan, the attacker looped create-then-cancel to accumulate approvals, then called the token's transferFrom directly to drain funds belonging to other campaigns out of the contract.
- CRITICALWEB3-NOMAD-2022
On August 1, 2022, the Nomad token bridge was drained of roughly $190 million in a few chaotic hours, and it became the first large crypto theft to turn into an open, crowdsourced free for all. Nomad processed cross chain messages in two steps: prove (record a message under a confirmed Merkle root) then process (execute it). A contract upgrade initialized the Replica contract with a committed root of bytes32(0), the empty tree root, and the initializer wrote confirmAt[bytes32(0)] = 1, permanently marking the zero root as trusted. Because any unproven message hash reads back the Solidity default of bytes32(0), the validity check acceptableRoot(0x00) returned true for every message that was never proven. Attackers skipped prove() entirely and called process() with crafted calldata, releasing funds with no Merkle proof at all. After the first transaction, anyone could copy it, swap in their own address and rebroadcast, so hundreds of opportunists piled in. Bridge TVL fell from about $190.7 million to under $2,000, and only roughly $36 to $39 million (about a fifth) was ever returned.
- CRITICALWEB3-PROXY-COLLISION-2022
On July 23, 2022 the Audius governance, staking, and delegation contracts on Ethereum mainnet were drained of 18,564,497 AUDIO (~$6.1M) because their upgradeable delegatecall proxy had a storage-layout collision with a re-callable initializer. A delegatecall proxy runs the logic contract's bytecode against the proxy's own storage, so the two contracts must agree on every slot index; Audius added a variable to the proxy that occupied the same low slot the implementation used for the OpenZeppelin Initializable initialized flag. Writing the proxy-side value reset the implementation's initialized boolean to a non-true state, removing the one-time guard, so the attacker re-invoked initialize() against an already-deployed contract. Re-initialization let the attacker register themselves as governance guardian and submit a malicious proposal that delegated enormous voting weight and executed an immediate treasury transfer. The contracts had been audited by OpenZeppelin and Kudelski but the collision was introduced later and missed.
- CRITICALWEB3-LIFI-2022
On 20 March 2022 the LI.FI swap/bridge router was exploited for about $596,000 from 29 wallets that had granted token approvals to its CBridgeFacet contract. The swapAndStartBridgeTokensViaCBridge path let callers supply an array of swaps each carrying an arbitrary destination address and arbitrary calldata, which the contract executed with a low-level call() under its own context and with no target allowlist or selector check. The attacker passed a tiny legitimate swap followed by calls whose target was an ERC-20 token and whose calldata was transferFrom(victim, attacker, amount). Because victims had given infinite approval to CBridgeFacet, those transferFrom calls succeeded, draining their wallets directly. This is the arbitrary-external-call / untrusted call-target router bug that weaponizes user approvals.
- CRITICALWEB3-KELPDAO-LAYERZERO-2026
On April 18, 2026, North Korea's Lazarus Group drained about 116,500 rsETH (roughly $292 million) from KelpDAO's LayerZero-based bridge, the largest DeFi exploit of the year. No smart contract was broken; the contracts did exactly what they were written to do. The attack was against the bridge's off-chain verification. rsETH's LayerZero channel was configured to trust a single verifier (a 1-of-1 DVN), so the attackers compromised LayerZero's internal RPC nodes, knocked out the honest external node with a denial-of-service flood, and forced that single verifier to attest to a cross-chain message that never really happened. The Ethereum side then released unbacked rsETH from escrow, leaving wrapped rsETH stranded across more than twenty chains and triggering a bank-run across DeFi.
- HIGHWEB3-FRONTEND-DNS-HIJACK-2022
A frontend hijack leaves the on-chain contracts untouched but replaces the Web2 surface serving the dApp UI with a wallet-drainer clone, so no Solidity audit can catch it. The recurring pattern: attackers take over the domain registrar or DNS provider account (or a CDN/tag-manager account), repoint the domain to a cloned site, and prompt visitors to sign malicious token approvals, EIP-2612 permit signatures, or transfers. Curve Finance was hit twice: on August 9-10, 2022 its curve.fi domain was DNS-hijacked via a compromised nameserver and drained ~$570K in USDC/DAI; and again around May 12, 2025 at the registrar level, after which Curve permanently migrated to curve.finance and announced an ENS move (Convex Finance and Resupply, which depend on Curve's data feeds, suffered dependency-driven outages but were not themselves compromised). In July 2024 a mass wave hit DeFi domains registered through Squarespace, whose forced migration off Google Domains stripped 2FA: Compound's frontend redirected to an Inferno Drainer clone and 100+ protocols were exposed (Celer blocked its takeover via domain monitoring). Ambient Finance's domain was hijacked through stolen registrar credentials on October 17, 2024. Most recently, on April 14, 2026 attackers used forged identity documents to social-engineer the registrar into handing over DNS control of CoW Swap's swap.cow.fi and cow.fi domains, redirecting users to a pixel-perfect drainer clone for about 90 minutes; over $1M was taken in roughly three hours, including 219 ETH (~$750K) from a single wallet, while CoW's contracts, backend APIs, and solver network were untouched. The same bucket includes CDN-account injections (KyberSwap's September 2022 Cloudflare/Google Tag Manager compromise, ~$265K) and BGP route hijacks that swap signed bundles for drainer code.