Decode, replay and refuse EIP-7702 delegations.
Built from the raw bytes of the @binance 2026-10-29 drain.
C4PzJjgHzw16shEnUyw5PzbsAMWAyvbcNzn8N1Dszg3n
We pulled the Binance drain apart byte by byte: why only one of the 50 EIP-7702 signatures landed, what the chain was showing for almost 4 hours, the Solana side, and where a signer gets to say no. Everything reruns with npx ef0100. https://t.co/m96sQKAApW
Funds are SAFU, they said.
OK, but is the thing holding the key SAFU?
ef0100 0.1.5 ships as a GitHub Action. Put it on a cron and if one of your addresses picks up an EIP-7702 delegation on any of 11 chains, the next run goes red. It only reads public chain data, never asks for a key.
uses: ef0100dev/[email protected]
ef0100 0.1.3 is on npm.
watch --webhook: every alarm and every clear goes to Slack, Discord or your own relay, as JSON.
https only. No redirects. The URL is never printed.
Also in this release: 6 guard invariants and pnpm bench. 117 tests.
Published from GitHub Actions, with provenance.
Every Solana attack transaction bundled with ef0100, checked before signing:
Drift, pre-signed tx #1: BLOCK.
Drift, pre-signed tx #2: BLOCK.
SwissBorg/Kiln hidden stake authorize: BLOCK.
Owner-change phishing: BLOCK.
Binance's 965,455.1 SOL leg, against its routine: BLOCK.
The same parser took 300,000 damaged copies of these transactions. 0 crashes.
The Oct 29 drain had a Solana leg: 965,455.1 SOL out of Binance's hot wallet in one transfer.
ef0100 sol, run with that wallet's own routine:
TEMPLATE_DRIFT. Its withdrawals advance a durable nonce from its own pool; this one used a recent blockhash.
BALANCE_FRACTION. 90.4% of its SOL.
Verdict: BLOCK.
Its normal batch 20 minutes later: OK.
New tests merged: guard invariants.
Six rules, each against 20,000 random authorizations:
chain_id 0: never signed.
A nonce other than the live one: never signed.
An unlisted delegate: never signed.
Over the rate limit: never signed.
After the key's own code changes: only the clear.
0 violations.
New in the repo: pnpm bench.
Asking the ef0100 guard about tuple #15 costs 16 µs (median, p99 48 µs).
One secp256k1 signature recovery costs 1,637 µs.
So the check in front of your key is about a hundredth of the work a node already does per tuple.
We threw 510,000 hostile inputs at ef0100.
Damaged copies of the real 4,916-byte transaction.
Mangled preimages of tuple #15.
Random digests.
Authorizations signed by viem with random keys.
0 failures. Every run is seeded, so a failure would name its input.
ef0100 0.1.2 is on npm.
New: watch. It asks 11 chains every 12 s whether an address is delegated, and prints a line when that changes.
On Oct 29 the first sweep came 17 blocks after the delegation.
Published from GitHub Actions, with provenance.
npx ef0100 watch <address>
A compromised laptop asking a signer for bytes is the case a signing guard is for.
ef0100 sits in front of the key and decides from the bytes:
A bare digest: refused.
An EIP-7702 authorization to an unlisted delegate: refused.
A key whose own code changed: signs only the clear.
It can't help if the key itself leaves.
Investigation update: Our initial investigation suggested that the security incident may have involved a compromised laptop, however our subsequent investigation has uncovered additional points of breach.
This was a complex attack, and we are doing all we can in coordination with law enforcement to resolve it. We are still gathering the facts, and will share more directly as we have them.
Binance will cover all losses from the SAFU fund and the company’s funds. User funds are safe.
We are still on track towards the expected timeline to resume the withdrawal service in 45 hours. Deposits remain unaffected.
The outflows ceased when we paused withdrawal service earlier. We are still working with partners to freeze many of the impacted assets, and have frozen around $3 billion thus far.
We will continue to provide further updates through official Binance channels as more verified information becomes available.
Oct 29: one @binance hot wallet key signed 50 EIP-7702 authorizations.
#15 applied. The wallet's code pointed at a sweeper for 1,142 blocks.
The same 50, behind ef0100:
REFUSE 50/50.
And once a key's own code changes, it signs only the clear.
npx ef0100 guard test
https://t.co/mewNz0fkco
While the wallet was delegated, the chain said so four ways:
eth_getCode returned 0xef0100 + the delegate.
The wallet emitted logs, which an EOA can't.
A plain ETH transfer in cost 21,062 gas, not 21,000.
Its own txs fell from up to 8 a block to 1.
All public for 1,142 blocks.
same 32 bytes, two signing paths.
a raw-digest signer sees 32 bytes.
the 0x05 that marks an EIP-7702 authorization is hashed in.
it signs.
the ef0100 guard wants the preimage.
no preimage, no signature.
npx ef0100 oracle runs the left side with a public test key.
the name is the bytes.
after #15 applied, the hot wallet's code became 23 bytes:
0xef0100 + the delegate's address.
for 1,142 blocks, any call to the wallet ran the delegate's code.
then a clear at block 26,301,896 wiped it.
ef0100 is named after those first three bytes.
we pulled that transaction apart.
50 authorizations, 50 nonces counting down from 18,914,824.
the wallet's nonce at that moment: 18,914,809.
#0 to #14 were ahead of it.
#15 matched and applied.
#16 to #49 were already behind.
all 50 recover to the same hot-wallet key.
🚨 JUST IN: Binance’s $2.5B hack may stem from a compromised signature system, not stolen private keys, says Blockaid CEO Ido Ben-Natan.
The attacker reportedly bundled 50 EIP-7702 authorizations into one transaction to hijack a Binance wallet.
Binance has yet to confirm the exact method.
https://t.co/BfubSkSFzM
@binance hacked: one transaction, 50 EIP-7702 signatures.
Only 1 applied. It was enough.
We decoded every byte of it and built the guard that refuses all 50.
$EF0100 is live.
CA: C4PzJjgHzw16shEnUyw5PzbsAMWAyvbcNzn8N1Dszg3n
Code: https://t.co/gt4hwAEj1Q