At 20:20:59 UTC on 29 October a transaction that moved no ether and called nothing landed in Ethereum block 26300753. Its only payload was an EIP-7702 authorization list, fifty entries long. EIP-7702 is the change Ethereum shipped in May 2025 that lets an ordinary account hand its execution to a contract, and every one of the fifty entries was signed by Binance 14, one of the exchange’s busiest hot wallets, naming a contract deployed that afternoon. Three minutes and twenty-four seconds later the contract emptied the wallet in one call: 167,464 ETH and 63 tokens, 1.615 billion USDT among them, somewhere between $2.5 and $2.8 billion at explorer prices that evening, to an address that had never received anything.
By 21:09 that night 0xQuit had already argued that whoever did this did not hold the key, because someone holding the key would not have needed a second account to carry the signatures on chain. The fifty entries put a time on the signing, and that time is most of what the chain can say about the question Binance’s first statement answers only in part: whether anyone ever had the key.
I pulled the raw transaction from a node that evening and pasted it into the raw transaction decoder on this site, which runs in the browser and names every byte. It showed fifty entries to one delegate and nothing about who had signed them, so I recovered the fifty signers with seventy lines of Python. The decoder does that itself now and shows the exact bytes each key signed. This transaction, decoded, is one of its examples. So is the sweep: one call from the carrier to the wallet, with a function selector that no public signature list knows, carrying the destination and sixty-five addresses, the zero address for ETH and then sixty-four token contracts. The decoder cannot name the function, so it reads that layout from the bytes.
Twenty-nine bytes
An EIP-7702 authorization is not a transaction. It is a signature over this:
05 EIP-7702 magic byte
db RLP list, 27 bytes follow
01 chain id 1
94 63e842b054bd624a465454d533c33f573e9c6fae delegate: 20-byte address
84 01209df9 nonce 18914809
Hash those twenty-nine bytes, sign the hash with the wallet’s key, and anyone can carry the result on chain in a type-4 transaction, the kind added for this purpose, and pay the gas: 0.0065 ETH for all fifty. The carrier here was 0x7C86…5CA0, an address that was empty two days earlier. What filled it was Tornado Cash: three withdrawals from the 0.1 ETH pool, at 07:39 and 08:53 UTC on 28 October and 08:23 on 29 October, each sent by a different relayer and each naming the carrier as the recipient, 0.294 ETH once the relayers had taken their fees. The first one, decoded, is a plain withdraw call: the pool, a 256-byte proof, a Merkle root, a nullifier hash, the recipient, the relayer and its fee. That is where the gas for the fifty authorizations came from.
A signing service that is handed 32-byte digests, the hashes it signs without seeing what they hash, cannot tell this one from a transaction hash. A policy engine that checks destination, amount and the data field never gets a look, because the object has none of those. What the signature grants is “run that contract’s code as me” once the nonce matches, and the code stays attached until another authorization replaces it.
Fifty nonces
Each entry is only valid if its nonce, the count of transactions the account has sent, equals the account’s nonce at the moment the carrier executes. Binance 14 is not a quiet account. In the three minutes before the attack it sent 33 transactions, about one every six seconds, so any nonce you name is stale by the time the signature comes back. The attacker’s answer was to sign a window, nonces 18914775 through 18914824, fifty in a row, listed in descending order.
It had practised. The carrier’s first nine transactions that day, from 02:28 UTC, deploy a sweeper, delegate two throwaway accounts to it with windows of two and three nonces, sweep a few dollars out, then deploy a revised sweeper at 15:59 and run the whole thing once more on a third throwaway. Those throwaways sent nothing of their own, so a window of one would have served and the tooling used two or three. Pointed at Binance 14 it used fifty, and needed thirty-five of them.
The low end dates the batch. Nonce 18914775 became the wallet’s live nonce in block 26300737, at 20:17:47, three minutes and twelve seconds before the carrier was broadcast. By the time the carrier was included the wallet had moved on to 18914808 and spent it on its own transaction, five places earlier in the same block. The sixteenth entry took effect. Thirty-four were already dead and fifteen were spare.
This is the decoder’s view of that entry, trimmed, with the warning it raises for the list as a whole:
authorization 15 0x63e842B054Bd624a465454D533C33F573e9c6fAe chain id 1, nonce 18914809
signed message 05db019463e842b054bd624a465454d533c33f573e9c6fae8401209df9
authority (recovered) 0x28C6c06298d514Db089934071355E5743bf21d60
warning: 50 authorizations from one account, all delegating to 0x63e8…6fAe,
with consecutive nonces 18914775 to 18914824
Paste the hex in yourself and hover any line to see which bytes it came from. Nothing leaves the page.
That window is the finding. A fifty-wide window is what you build when you submit digests to something and do not control when, or how fast, the signatures come back. I read it as a signing path that was handed fifty digests and returned fifty signatures in the ordinary course of its work. When I first wrote that, Binance had not said how the signatures were obtained, and a post-mortem could still have described a plain key theft with an oddly cautious operator behind it.
Four more chains
Twenty-four seconds after the sweep, Binance 16 sent nine ordinary transactions to the same collector in a single block: eight token transfers and 28,005 ETH, consecutive nonces, 170 gwei each, no delegation anywhere. Blockaid counts nine more hot wallets on Arbitrum, Optimism and Avalanche doing the same within twelve minutes. I checked Binance 16 and take the rest on their word.
The next morning I checked three chains that have nothing like EIP-7702. On the XRP Ledger, five Binance wallets paid 233.5 million XRP to one account between 20:05:00 and 20:09:20, a quarter of an hour before the delegation was broadcast. The attacker’s first attempt there, at 20:04:52, was 42.75 million RLUSD, Ripple’s dollar stablecoin, and it failed with tecNO_DST: the receiving account did not exist yet, and on that ledger a token payment cannot create one. The 185 million XRP sent eight seconds later could, and did. On Solana, 965,455 SOL left Binance 2 at 20:10:18. On Bitcoin, block 973732 spends 513 coins from Binance’s main hot wallet, bc1qm34…, 18,270 BTC, to a fresh address that split it into seventeen pieces of exactly 1,000 BTC before the block closed. That is 513 signatures over payments to an address the wallet had never seen.
So the order was XRP at 20:05, Solana at 20:10, Bitcoin at 20:20, and the delegation last, at 20:20:59. On every other chain, whatever did the signing signed plain transfers to addresses that were an hour old, or eight seconds old. Binance 14 alone got the 7702 route. Either the attacker held every key and used a delegation on this one wallet because sixty-three tokens are easier to take in one call, or Binance 14’s signer sat behind a policy that would refuse a transfer to a new address and had no opinion about an authorization. The chain cannot tell those apart. That was the question I wanted the post-mortem to answer.
What Binance said
Update, 30 October, 02:25 UTC. Binance’s initial finding is that a DevOps engineer’s laptop was compromised, that the attacker used it to reach a service container and submit withdrawal transactions through it, and that there is “no evidence of any wallet private key leak”. The wording is hedged, “suggests” and “may involve”, and the technical post-mortem is still to come. If it holds, it is the second reading: nobody stole a key. The attacker fed requests to the pipeline that owns the keys, and the pipeline signed fifty authorizations for Ethereum and plain payments for every other chain, which is what the fifty-wide window looked like from outside. The question for the post-mortem is then how a withdrawal service came to put a signing request beginning with 0x05 in front of the signer at all. The statement puts the total at about $6.3 billion with about $3 billion frozen, and the address authorisation it says it revoked is the reset at 00:10:35 below.
Update, 3 November, 23:15 UTC. Binance’s initial report, published on 3 November, answers that question: the signer, not the withdrawal service. The chain it describes starts in June, when an engineer on the wallet infrastructure team installed a tampered Homebrew package while looking for an AI coding tool. Binance says it caught that one, replaced the device and rotated credentials, but by then the attacker knew who ran the wallets. In September a second engineer was approached on a job-hunting platform by a “Project Director”, interviewed on video by a fake HR person and then by the fake CEO of a fictitious company, and asked at the end of the second interview to download an assignment onto his work computer. Its setup swapped a pyenv component for a malicious one and reported home, and endpoint protection did not see it. On 20 October the attacker used that machine and an internal AI tool to reach the first engineer and a third, and found a container deployment token on the first engineer’s computer. Between 17:15 and 19:56 UTC on the 29th the attacker logged on to the third engineer’s computer, deployed a container with the stolen credentials and ran a script, and from there had what the report calls “unauthorized access to an internal wallet signing service”, used to start transactions that never went through the withdrawal process.
That is the second reading, with the surface named: requests reached the signer without passing the pipeline and whatever policy sits in it. Of the fifty entries the report says the attackers “submitted 50 signing transactions to manipulate the account nonce”, which is the fifty-wide window seen from inside, fifty requests in and fifty signatures out from someone who could not know which nonce would be current when the batch landed. It also explains the three hours and forty-six minutes between the sweep and the reset at 00:10:35. The wallet is an MPC wallet, so there was no single key to sign a revocation with, and the team had to build and run a revocation procedure while the delegation kept working, which is why suspending withdrawals and shutting down the hot wallet services did not stop the outflow. The report puts the loss at $6.34 billion with $2.85 billion frozen, cites the FBI for an attribution to North Korea, and lists signing policy coverage and hot wallet controls among the things under review. It does not say what the signing service checked before it signed, and it promises further information rather than a fuller post-mortem.
What the signer saw
Someone will say this is Bybit again. In February 2025 Bybit’s signers approved what looked like a transfer and was a contract upgrade, $1.5 billion went, and the lesson everyone drew was to show the signer the data field of every transaction. Mostly, yes, with a 7702 delegation as the sweep instead of a proxy upgrade. Except that here there is no data field to show. Twenty-nine bytes, a prefix and three fields, is the whole object, and showing it faithfully gets you “chain 1, that address, nonce 18914809”. Refusing it means knowing what sits at that address.
I counted what a hot-wallet signing policy would need to check to have stopped this. The list is eight items. The second is to parse the full input of everything the key signs and route anything that starts with 0x05 to its own rules, and no policy template I have seen has a line for it.
Binance’s own systems kept sending the wallet’s normal traffic afterwards, and deposits kept arriving: 326 USDT transfers after the drain, one of them 200 million at 21:42:59, swept 72 seconds later. A wallet that signs ten things a minute will sign the eleventh, and the only question a review can answer is what it was shown, which here was designed to be almost nothing. At 23:50 UTC, three and a half hours after the drain, Binance 14 was still running the attacker’s contract. Binance cleared it at 00:10:35 with one authorization to the zero address, then suspended withdrawals and promised a post-mortem.
Correction. An earlier version counted thirty-three dead entries and sixteen spare, said Blockaid counted ten wallets on the three other chains, and gave the time of 0xQuit’s post as 22:09. The counts are thirty-four and fifteen, since nonce 18914808 was spent in the attack block itself. Blockaid’s ten includes Binance 16 on Ethereum. The post was at 21:09 UTC.