Skip to content

Key, signer and infrastructure attacks

The largest losses of recent years were not contract bugs. A signer approved something other than what its screen showed, or a single machine or RPC lied. The fix is independence: several parties that each read the raw transaction and can each refuse.

A private key is like an SSH key with money behind it. It cannot be revoked or reset, and whoever has it is you. The industry answered with a series of controls, and attackers moved one step up each time.

  1. Single key. One stolen key loses everything.
  2. Multisig. M of N keys must sign, enforced by a contract. Attackers responded by compromising several signers at once (Ronin 2022, 5 of 9 keys).
  3. Hardware wallets. Keys cannot be copied off the device. Attackers stopped stealing keys and started changing what the signers see: the device signs a hash, and the screen that explains the hash belongs to a compromised web UI (Radiant 2024, WazirX 2024, Bybit 2025).
  4. Pre-signed transactions. Convenient for operations. Attackers collected signatures in advance through social engineering and used them later (Drift 2026).
  5. Off-chain verifiers and RPC. A service that attests “this happened on chain A” believes its RPC nodes. Poison the nodes and the service signs a lie (KelpDAO 2026).

In every case the contracts did what they were told.

  1. Attackers compromised a Safe{Wallet} developer’s machine.
  2. They swapped the JavaScript served from Safe’s S3 bucket. The malicious code targeted Bybit’s wallet.
  3. Bybit’s signers opened the usual web UI. It showed a normal transfer.
  4. Their devices signed what the UI built: a delegatecall to an attacker contract.
  5. A delegatecall runs foreign code on the wallet’s own storage. That code replaced the Safe’s implementation address.
  6. The wallet now ran the attacker’s code. About $1.46B was drained.

The screen said X and the signature meant Y.

BYBIT, FEB 2025: WHAT HAPPENED Tampered web UIshows: normal transfer Signers' devicessign what UI built Safe contractruns: delegatecall Wallet code swapped$1.46B drained screen said X, signature meant Y INTENT → VALIDATOR → SIGNER: WHAT STOPS IT Intentmove 1,000 ETH to X Validatordecodes raw calldata Signerre-checks own policy Chainonly what was meant delegatecall not in intent → reject separate infra, separate team
Bybit's signers trusted one screen. In the bottom design, two independent services each read the raw transaction and each can refuse, so a compromised UI or a compromised validator alone is not enough.
  1. Intent. The request is recorded in plain terms first: “move 1,000 ETH to X”.
  2. Validator. A separate service takes the raw transaction, decodes the calldata itself, simulates it on a fork, and compares the result with the intent and with policy: no delegatecall, no admin functions, destination on an allowlist, amount within limits. Anything not in the intent is rejected.
  3. Signer. The signing service re-checks its own policy on the same raw bytes before it signs. It runs on separate infrastructure, owned by a separate team.
  4. Chain. Only what was meant gets through.
  5. Timelock. Admin actions go through a delay, so a bad signature still leaves a window to react.

Treat the signing UI as untrusted. It is a convenience for humans, not a source of truth.

Loss figures are approximate, at the time of the attack.

Incident Loss What happened The control that would have stopped it
Bybit, Feb 2025 about $1.46B Safe{Wallet} developer machine compromised; JavaScript on their S3 bucket swapped. Signers saw a normal transfer and signed a delegatecall that replaced the Safe’s implementation. Decode and simulate the raw transaction on an independent device; verify the Safe transaction hash outside the web UI; a policy that rejects delegatecall and implementation changes from a cold wallet used for routine transfers.
Radiant, Oct 2024 about $50M Malware on three signer devices; the UI showed benign transactions, hardware wallets signed an ownership transfer. Clear signing on hardware, independent transaction verification, timelock on ownership changes.
WazirX, Jul 2024 about $230M The multisig signing UI showed different data from what was signed; the contract was upgraded. Same: do not trust one UI, verify calldata independently.
Drift, Apr 2026 about $285M Months of social engineering of contributors; signers pre-signed transactions using Solana durable nonces; these were later used to hand admin to the attacker. Never pre-sign; admin changes behind a timelock; signer devices managed and isolated; per-transaction policy, not per-person trust.
KelpDAO, Apr 2026 about $292M The rsETH bridge route was verified by a single (1-of-1) LayerZero verifier whose RPC infrastructure was poisoned; a forged message released funds. Kelp and LayerZero dispute who chose the setup. Multiple independent verifiers on independent RPC; no single node’s view of the chain decides money.
Ronin, Mar 2022 about $625M 5 of 9 validator keys taken, one through a fake job offer PDF; noticed six days later. Key diversity across organisations, outflow monitoring that pages in minutes.
Model How it works Where it is enforced What the chain sees Fails when
Single EOA key (hot wallet) One private key in a file, a KMS or a hardware wallet Nowhere beyond possession One signature The key or the machine using it is compromised
Multisig (for example Safe) The 2-person rule for prod: M of N keys must sign On-chain, in the wallet contract’s code A contract call carrying M signatures M signers are tricked or compromised together, often through one shared UI
MPC (multi-party computation) A split key; the whole key never exists in one place Off-chain, among the parties holding shares One normal signature One operator controls enough shares (Multichain 2023), or all parties sign what one compromised service asked for
Multisig or MPC plus timelock As above, and the action only takes effect after a delay On-chain delay A queued action that anyone can see Nobody watches the queue, or the delay is set to zero
Intent, validator, signer Any of the above, with independent policy checks on the raw transaction before signing Off-chain, in two separate services Only transactions that match a recorded intent Validator and signer share infrastructure, code or a team
Method What is shown What it protects against What it misses
Blind signing A hash, or nothing Nothing Everything; the signer approves whatever was built
UI summary The web app’s description of the transaction Honest mistakes A compromised web app describes one thing and builds another
Clear signing The device decodes the fields and shows them on its own screen A lying web UI Calls the device cannot decode; meaning that only shows in simulation
Independent decode and simulation A second system decodes the raw calldata and simulates the state change A lying UI and unexpected side effects such as an implementation change A compromise of that second system, unless the signer also checks
Hash check outside the UI The Safe transaction hash is recomputed from the intended fields and compared with the hash on the device A UI that swaps the transaction Mistakes in the intended fields themselves
Symptom Cause Check
A signing request has a long opaque data field You do not know what it calls cast 4byte-calldata $CALLDATA, or cast decode-calldata "f(address,uint256)" $CALLDATA when the signature is known
A Safe transaction for a routine transfer has operation = 1 It is a delegatecall, not a call. In Safe, operation 0 is call and 1 is delegatecall. Reject by policy unless the target is on a short allowlist
A transfer request targets an unknown contract instead of the token or the recipient The UI built something other than what it shows Compare to, value and decoded arguments with the intent
After a signed transaction, the wallet behaves differently Its implementation was replaced cast storage $SAFE 0 reads slot 0, where a Safe proxy keeps its implementation (singleton) address; compare with the known value
Ownership or admin changed with no change ticket Pre-signed or socially engineered transaction Alert on OwnershipTransferred and RoleGranted on contracts, AddedOwner, RemovedOwner and ChangedThreshold on a Safe
A verifier or bot acted on an event that never happened Its RPC was poisoned or lagging Compare block hash and balances across two or more providers plus your own node. See Chain mechanics.
Funds left days ago and nobody noticed No outflow monitoring Alert on outflows against a baseline, paging within minutes

Operational rules that follow from the incidents:

  • Never pre-sign anything except a pause. See Defence stack.
  • Put ownership, admin and upgrade changes behind a timelock. See Proxies and upgrades.
  • Spread keys across organisations and devices, not across people in one company on one fleet of laptops.
  • Policy is per transaction, not per person. A trusted person on a compromised machine signs what the attacker wants.
  • No single node’s view of the chain decides money.

private key, signer, blind signing, clear signing, hardware wallet, multisig, Safe, Safe{Wallet}, threshold, M of N, MPC, threshold signature, key share, timelock, delegatecall, operation 1, singleton, implementation swap, UI tampering, supply chain, S3 bucket, intent, independent validator, calldata decoding, transaction simulation, policy engine, allowlist, pre-signed transaction, durable nonce, social engineering, fake job offer, RPC poisoning, DVN, 1-of-1 verifier, outflow monitoring, OwnershipTransferred, Bybit, Radiant, WazirX, Drift, KelpDAO, Ronin, Multichain, Lazarus, TraderTraitor.