Binance's $3.3B wallet transfers: what the chain shows, and how to tell a hack from a move
Read from a public Ethereum node: an EIP-7702 delegation on the Binance 14 address, a 65-token sweep, and Tether and Circle freezes. Signs that separate theft from an internal move.
By the Maborak engineering team · · 10 min read
On 29 October 2026 about $3.3 billion in tokens left wallets that block explorers label as Binance’s, and the question “was Binance hacked?” spread faster than any answer. Binance said it was investigating a “potential security issue” and later that “user funds are completely safe”. It has not said what the transfers were. This post does not answer the question either. It shows what anyone can read from the chain, explains the mechanism the transfers used, and lists the signs that would separate a theft from an internal move.
Checked 29 October 2026, at Ethereum block 26,301,820 (23:55 UTC). Every transaction, account state and freeze below was read from a public Ethereum node with the scripts in the Probe section and is marked [reproduced]. Statements by Binance and Tether reached this post through press reports and are marked [reported]. Conclusions are marked [inferred], with the reasoning shown. The incident is still open.
Background
The address 0x28c6c062…1d60 has long carried the explorer label “Binance 14”, and 0xee7ae85f…4055 the label “Binance: Hot Wallet 34”. Labels are assigned by analytics firms, not by Binance, so they are strong hints, not proof of ownership. [reported]
Binance’s first statement, reported at 5:16 p.m. ET (21:16 UTC), said its teams were “actively investigating” a “potential security issue” and had “not confirmed any impact to user funds”. A version reported at 5:29 p.m. ET said: “User funds are completely safe.” Tether’s CEO said Tether had frozen more than 1.567 billion USDT linked to the transfers. [reported]
Mechanics
What happened on chain
All times are UTC on 29 October 2026, taken from the block timestamps. [reproduced]
| Time | Block | What the chain records |
|---|---|---|
| 20:20:59 | 26,300,753 | 0x7c86…5ca0 sends a type-4 (EIP-7702) transaction carrying 50 signed authorizations that delegate “Binance 14” to contract 0x63e8…6fae |
| 20:24:23 | 26,300,770 | 0x7c86…5ca0 calls sweep(address,address[]) on “Binance 14”: 65 token contracts, including 1,615,409,498.97 USDT, go to 0x5227…2f8c |
| 20:30:11 | 26,300,799 | 0x5227…2f8c sends 500,000,000 USDT to 0x9749…c762, then 200,000,000 USDT to 0x0ddf…697e at 20:33:23 (block 26,300,815) |
| 20:38:47 | 26,300,842 | 0x5227…2f8c sends 195,460 ETH to 0x8532…43d4 |
| 20:41:23 | 26,300,855 | 780,000,000 USDC moves from “Hot Wallet 34” to 0x5227…2f8c |
| 21:01:35 | 26,300,954 | Tether freezes 0x5227…2f8c and 0x9749…c762, then 0x0ddf…697e one block later, and six more addresses by block 26,301,041 |
| 21:04:59 | 26,300,971 | Circle freezes 0x5227…2f8c |
| 22:06:23 | 26,301,278 | Tether freezes “Binance 14” itself |
| 23:53:35 | 26,301,812 | Circle freezes “Binance 14”, then “Hot Wallet 34” at 23:54:59 (block 26,301,819) |
The transfers did not come from a transaction signed by “Binance 14”. They came from calls to it, by a separate account, 0x7c86…5ca0, which had sent 21 transactions in total at the time of the check.
EIP-7702: how a signature becomes code
EIP-7702, a final Ethereum standard that is active on mainnet (the 20:20:59 transaction is one), lets an ordinary account delegate to contract code. A type-4 transaction carries a list of authorizations. Each one is a signature, by the account’s own private key, over keccak(0x05 || rlp([chain_id, address, nonce])). If the signature recovers to the account and the nonce matches the account’s current nonce, the network writes 0xef0100 followed by the contract address into the account’s code. From then on, calls to the account run that contract’s code, until the account signs another authorization that changes or clears it. [vendor], from the EIP-7702 specification.
“Binance 14” now has exactly that code: 0xef0100 followed by 0x63e842b054bd624a465454d533c33f573e9c6fae. [reproduced] The 50 authorizations in the 20:20:59 transaction cover consecutive nonces from 18,914,775 to 18,914,824. “Binance 14” is a busy account (its nonce was 18,914,902 at the check), and signing a range is one way to be sure one authorization matches the nonce at the moment the transaction lands. [inferred]
What this proves, and what it does not:
- It proves that whoever prepared the delegation could obtain valid signatures from the “Binance 14” key, or from the system that signs for it. EIP-7702 accepts no other signer.
[inferred], from the specification. - It does not prove who that was. Binance’s own operations could use EIP-7702 for a wallet migration; an attacker with access to the key or to the signing system could use it the same way. The chain records the signature, not the intent.
- The delegate contract is opaque.
0x63e8…6faehas no verified source on Blockscout, so its full behaviour cannot be read. Only thesweep(address,address[])call is visible.
Freezes: what stablecoin issuers can and cannot stop
USDT and USDC are tokens with a blocklist built into their contracts. Tether’s contract has isBlackListed(address) and Circle’s has isBlacklisted(address). A blocklisted address keeps its balance but cannot send it. Receiving is not blocked: after Tether froze 0x5227…2f8c, another 3,917,639.77 and 200,397,771.82 USDT arrived from “Binance 14”. [reproduced]
ETH and most other tokens have no such switch. The 195,460 ETH at 0x8532…43d4 cannot be frozen by anyone; that address had never sent a transaction at the time of the check. [reproduced]
Impact
For Binance users, the only on-record position is Binance’s: user funds are “completely safe”. [reported] Nothing on chain contradicts or confirms that, because exchange balances are an internal ledger, not on-chain data.
On the money, at block 26,301,820: [reproduced]
0x5227…2f8cheld 1,175,464,711.08 USDT and 823,000,000 USDC, frozen in both.- The nine addresses Tether froze held 1,381,816,113.41 USDT in total, below the “more than 1.567 billion” Tether’s CEO reported. The difference may sit in addresses this search did not find, or reflect balances at the time of each freeze.
[inferred] - 700 million USDT left
0x5227…2f8cat 20:30 and 20:33, about half an hour before the first freeze. Tether froze both receiving addresses within a block of the first freeze; they held no USDT at the check. - 195,460 ETH sits at an unfreezable address.
For anyone running hot wallets on Ethereum, the incident shows a property of EIP-7702 that predates it: a key that can sign transactions can also sign a delegation, and a delegation turns one signature into standing code on the account. A signing policy that reviews outgoing transfers but not authorization payloads does not see it. [inferred], from the specification.
Hack or move: the signs
| Sign | Points toward theft | Points toward an internal move | Seen so far |
|---|---|---|---|
| Destination | Fresh accounts with no history | Known, labelled company wallets | Fresh accounts: 0x5227…2f8c had 24 transactions at the check, 0x8532…43d4 none [reproduced] |
| Speed of onward movement | Splitting and moving within minutes | Funds parked | 500M and 200M USDT and 195,460 ETH moved on within 15 minutes of the sweep [reproduced] |
| Issuer response | Freezes on the destination and the source | No freezes | Tether froze the destination, the onward hops and “Binance 14”; Circle froze the destination, “Binance 14” and “Hot Wallet 34” [reproduced] |
| Delegate code | Unverified, purpose unknown | Published or verified | Unverified [reproduced] |
| Exchange statement | Breach confirmed | Explanation of a migration | Neither yet; “funds are completely safe” [reported] |
| Service | Withdrawals paused or limited | Normal operation | Not established in the sources |
The issuers’ actions are the strongest public signal. Tether and Circle froze the receiving address within 41 minutes of the sweep, and both later froze the Binance addresses the funds came from. Issuers act on information this post does not have, and a freeze can also be a precaution requested by the exchange. [inferred]
Probe
Three short Python scripts using only the standard library and the public JSON-RPC endpoint https://ethereum-rpc.publicnode.com. They make read-only calls (eth_getTransactionByHash, eth_getTransactionReceipt, eth_getCode, eth_call, eth_getLogs) and change nothing. Python 3.15 was used; any Python 3 works.
1. What a transaction moved. It decodes ERC-20 Transfer logs from the receipt.
import json, sys, urllib.request
RPC = "https://ethereum-rpc.publicnode.com"
TRANSFER = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
TOKENS = {"0xdac17f958d2ee523a2206206994597c13d831ec7": ("USDT", 6),
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": ("USDC", 6)}
def rpc(method, params):
body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode()
req = urllib.request.Request(RPC, body, {"Content-Type": "application/json", "User-Agent": "probe"})
return json.load(urllib.request.urlopen(req, timeout=30))["result"]
for h in sys.argv[1:]:
tx, rc = rpc("eth_getTransactionByHash", [h]), rpc("eth_getTransactionReceipt", [h])
print(f"tx {h[:12]}… type={int(tx['type'],16)} from {tx['from']} to {tx['to']} ETH {int(tx['value'],16)/1e18:,.4f}")
for log in rc["logs"]:
if log["topics"][0] == TRANSFER and len(log["topics"]) == 3 and log["address"].lower() in TOKENS:
sym, dec = TOKENS[log["address"].lower()]
print(f" {sym} {int(log['data'],16)/10**dec:,.2f} 0x{log['topics'][1][-40:]} -> 0x{log['topics'][2][-40:]}")
Output for the sweep and the USDC transfer: [reproduced]
tx 0x53bd38b816… type=2 from 0x7c8601d4645b93cea45f71e118a729332e6b5ca0 to 0x28c6c06298d514db089934071355e5743bf21d60 ETH 0.0000
USDT 1,615,409,498.97 0x28c6c06298d514db089934071355e5743bf21d60 -> 0x5227f603c1ee34ce3c06efe6477003bdfccb2f8c
tx 0xdc102dd89d… type=2 from 0x7c8601d4645b93cea45f71e118a729332e6b5ca0 to 0x28c6c06298d514db089934071355e5743bf21d60 ETH 0.0000
USDC 780,000,000.00 0xee7ae85f2fe2239e27d9c1e23fffe168d63b4055 -> 0x5227f603c1ee34ce3c06efe6477003bdfccb2f8c
The sweep also moved 64 other tokens; the script prints only USDT and USDC.
2. Whether an account is delegated. eth_getCode returns 0x for a plain account, 0xef0100… for an EIP-7702 delegation, and contract bytecode otherwise. On the delegation transaction, authorizationList shows what was signed.
code = rpc("eth_getCode", ["0x28c6c06298d514db089934071355e5743bf21d60", "latest"])
print("delegated to 0x" + code[8:48] if code.startswith("0xef0100") else code[:20])
tx = rpc("eth_getTransactionByHash", ["0xad99264d5532ae0dd04b2004eebda05f25657e70dacb764f7ac8d4ccd051298b"])
auths = tx["authorizationList"]
print(f"type={int(tx['type'],16)} authorizations={len(auths)} delegate={auths[0]['address']} "
f"nonces={min(int(a['nonce'],16) for a in auths)}-{max(int(a['nonce'],16) for a in auths)}")
delegated to 0x63e842b054bd624a465454d533c33f573e9c6fae
type=4 authorizations=50 delegate=0x63e842b054bd624a465454d533c33f573e9c6fae nonces=18914775-18914824
[reproduced]
3. Whether a stablecoin balance is frozen. Read-only calls to the issuers’ own contracts: isBlackListed(address) (selector 0xe47d6060) on USDT, isBlacklisted(address) (0xfe575a87) on USDC, and balanceOf(address) (0x70a08231).
USDT, USDC = "0xdac17f958d2ee523a2206206994597c13d831ec7", "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
def call(to, selector, addr):
return int(rpc("eth_call", [{"to": to, "data": selector + addr[2:].lower().rjust(64, "0")}, "latest"]), 16)
for a in sys.argv[1:]:
print(a, "USDT frozen", call(USDT, "0xe47d6060", a) == 1, f"{call(USDT, '0x70a08231', a)/1e6:,.2f}",
"USDC frozen", call(USDC, "0xfe575a87", a) == 1, f"{call(USDC, '0x70a08231', a)/1e6:,.2f}")
0x5227f603c1ee34ce3c06efe6477003bdfccb2f8c USDT frozen True 1,175,464,711.08 USDC frozen True 823,000,000.00
0x8532fa14acaf483729c449b8458aeddb900543d4 USDT frozen False 0.00 USDC frozen False 0.00
0x28c6c06298d514db089934071355e5743bf21d60 USDT frozen True 1,351,530.01 USDC frozen True 52,363.12
[reproduced] The freeze events themselves (AddedBlackList on USDT, Blacklisted on USDC) and the onward USDT transfers in the timeline came from eth_getLogs on the two token contracts from block 26,300,700. The public node refuses historical state queries, so the scripts show current state only.
Mitigation
For exchange users:
- Read updates only on Binance’s own site and verified accounts. Incident windows bring messages offering “compensation” or “recovery”; Binance’s statements contain no such offer.
- Use an authenticator app or hardware key for two-factor authentication, turn on withdrawal address allowlisting, and remove API keys you do not use or restrict them to trading without withdrawal rights.
- Keep long-term holdings off any single exchange if counterparty risk matters to you; self-custody trades that risk for key-management risk.
For teams running hot wallets or signing services on Ethereum ([inferred], from the EIP-7702 specification):
- Refuse to sign authorization payloads you did not plan. An EIP-7702 authorization is a signature over a message starting with the byte
0x05. A signing policy, in an HSM or an MPC service, can reject that domain outright or require separate approval for it, the same way it gates large withdrawals. - Alert on account code. Poll
eth_getCodefor every hot wallet. Any result other than the expected one, especially0xef0100…, means the account is delegated and calls to it run someone’s contract. - Watch type-4 transactions that name your addresses in their authorization list, sent by accounts you do not control.
- Know the undo. A delegation stays until the account signs a new authorization. Pointing it at the zero address clears the code; that needs the same key, so plan the response before an incident.
Verification
Re-run the probes against the latest block. These outcomes would settle the question:
- An internal move: Binance publishes an explanation naming the delegate contract or the receiving addresses as its own, the freezes are lifted at Binance’s request, and “Binance 14” code returns to
0xor to a published contract. - A theft: Binance confirms a breach, funds keep moving from the unfrozen ETH address, and the delegate contract or the sender account turns up in other incidents.
Until one of these happens, check the facts that change: eth_getCode on “Binance 14”, the freeze status and balances of 0x5227…2f8c, and the nonce of 0x8532…43d4 (still 0 means the ETH has not moved).
Sources
- Transactions on Etherscan: delegation, 20:20:59 UTC, sweep, 20:24:23 UTC, ETH transfer, 20:38:47 UTC, USDC transfer, 20:41:23 UTC.
- EIP-7702: Set Code for EOAs (status Final).
- Token contracts: Tether USDT and Circle USDC.
- Binance’s statements as reported by Forbes and Yahoo Finance (29 October 2026); Tether’s freeze figure as reported by AMBCrypto.