Skip to main content
Security incident analysis
セキュリティ
暗号資産
アーキテクチャ設計
認証・認可
信頼性
決済

The Binance $6.3B Outflow (October 2026) Explained: Protecting the Key Is Not Enough — Designing a Withdrawal Policy That Guards the Signing Pipeline

The 29 October 2026 Binance hot-wallet outflow (about US$6.3 billion), reconstructed from official notices and on-chain records, and why protecting a private key and authorizing what gets signed are separate problems — with EIP-7702 delegation and a tested withdrawal policy engine.

Published
Reading time
25 min read
Author
友田 陽大
Share

On 29 October 2026, about US$6.3 billion in assets flowed out of the hot wallets of Binance, one of the world's largest crypto exchanges. By Binance's own account the compromise began at around 20:05 Coordinated Universal Time (UTC) — 05:05 on 30 October in Japan.

This article lays out the events and then digs into one point most write-ups skip: assets can leave even when private keys are stored safely.

The tools that protect keys (HSMs, MPC, KMS) protect against the key being taken. Deciding whether what is about to be signed is a legitimate withdrawal is a different layer's job. The on-chain record points to that second layer being tested. This article covers that record, and the design builders of transfer and payment systems should adopt, with code whose behavior is checked by tests.

Timing and sourcing. This article rests on primary sources as of 01:00 JST on 1 November 2026. Binance has not published a technical post-mortem and the root cause is not settled. It separates facts confirmed in official notices, analytics firms' assessments (reports and hypotheses) and the author's inference. The diagrams and code are a generalized reference model and not a reconstruction of Binance's internal architecture. The teaching code is not usable as a production asset-management system.

Key points in 30 seconds

  • What happened: Binance's hot wallets (internet-connected wallets used for instant withdrawals) were compromised and about US$6.3 billion left, across roughly ten chains.
  • The cause is not settled: the first update said the incident "may involve" a compromised DevOps engineer's laptop that let an attacker reach a service container and submit unauthorized withdrawal transactions. Update #2 the same day revised it: the subsequent investigation found additional points of breach.
  • Private keys: Binance says it has found no evidence of a leak so far. Absence of evidence is not proof that nothing leaked.
  • Three different states of money: about $3 billion was frozen on-chain by issuers. Binance replenished 90% of the outflow from its own funds. The amount recovered from the attacker has not been published.
  • Impact on users: withdrawals are suspended, with a phased reopening planned for 1 November. Deposits are said to be normal.

Before you hold real customer data

Web app & SaaS security audit — authorization, tenant isolation and config, verified in the code

Confirmed facts and timeline

Binance has published three official notices. The pages render in JavaScript, so the author checked them against the body text and publish/update times (UTC) returned by Binance's announcement API.

Time (UTC)JSTEventSource and classification
28 Oct, morning28 OctThe attacker's operating wallet is funded via Tornado CashCointegrity analysis (report)
29 Oct ~20:0530 Oct ~05:05Compromise of the hot wallets begins; first outflow on the XRP LedgerBinance update #2 (confirmed); chain per Cointegrity
29 Oct 20:20:5930 Oct 05:20:59An EIP-7702 delegation is set on the hot wallet "Binance 14"On-chain (confirmed; see below)
29 Oct ~21:0130 Oct ~06:01Tether freezes the main receiving walletCointegrity (report)
29 Oct ~22:27–22:3330 Oct ~07:27–07:33Withdrawals suspendedCointegrity (report); the suspension itself is confirmed in update #1
29 Oct 23:5630 Oct 08:56Deposits arriving at Binance 14 are swept for the last timeElliptic (report)
30 Oct 02:2330 Oct 11:23Update #1: laptop lead, no evidence of key leak, about $3B frozenBinance (confirmed)
30 Oct 11:3630 Oct 20:36Update #1 revised to say deposits are unaffected and operating normallyBinance (confirmed)
30 Oct 19:3331 Oct 04:33Update #2: 20:05 start time, about $6.3B, the laptop lead revised, 80% coveredBinance (confirmed)
31 Oct 14:2431 Oct 23:24Update #3: 90% replenished, Proof of Reserves snapshot, withdrawals to reopen 1 NovBinance (confirmed)

What changed between the first update and the second

The most important change is the account of how the attacker got in. Update #1 says:

initial investigation suggests that the security incident may involve a compromised DevOps engineer's laptop, which allowed an attacker to gain access to a service container and submit unauthorized withdrawal transactions.

Even then the wording is hedged: "may involve". Update #2 revised the explanation itself:

Our initial investigation suggested that the incident may involve a compromised laptop, however, our subsequent investigation has uncovered additional points of breach.

The "additional points of breach" have not been named. An article that quotes only the first update and says "the cause was a DevOps laptop" is already out of date.

Frozen, recovered and replenished are different things

Three words that are often mixed up in coverage:

StateMeaningAmountWhose money, and where
FrozenAn issuer (Tether, Circle, etc.) made tokens at the attacker's addresses immovableAbout $3B per Binance. Elliptic: $2.85B (44% of the theft). TRM: about $2.7BStill at the attacker's addresses. Not returned
RecoveredThe stolen assets themselves were taken backNot published—
ReplenishedBinance prepared the same assets from its own funds90% of the outflow (update #3); ten main assets at 100%Corporate treasury, the SAFU (user protection fund) and a futures insurance fund

Freezing worked almost only for USDT and USDC. Elliptic writes that "nothing stolen on Bitcoin, the XRP Ledger, Solana or NEAR has been frozen". That reflects a property of blockchains: tokens with a central issuer can be stopped; native assets cannot.

Binance's statement on private keys

Update #1 says "We have found no evidence of any wallet private key leak." Update #2 says "At this stage, we have found no evidence that wallet private keys were leaked." Update #2 added "At this stage".

This is not a statement that nothing leaked. The on-chain record below is consistent with the view that Binance's signing system was made to produce signatures the attacker wanted. But that alone cannot settle whether a key was taken out.

What is still unknown

  • The root cause, and the "additional points of breach" in update #2
  • Whether keys were taken, or the signing service was abused
  • How the attacker obtained the 50 pre-signed delegations described below
  • Whether deposits were also paused around 00:00 UTC on 30 October, as some reports say (Binance's own page was revised to say deposits were unaffected)
  • The breakdown of the replenishment funds (SAFU, insurance fund, treasury)
  • Who carried it out. TRM Labs attributes it to North Korea's TraderTraitor "with high confidence" and Elliptic says it is likely. Binance has not named anyone and no government attribution is confirmed. That is an analytics firm's assessment, not an established fact

Background: holding a key is not the same as being made to sign

Now the technical part. First, two prerequisites for non-engineers.

Hot and cold wallets

A hot wallet is connected to the network and can answer withdrawal requests automatically. To process user withdrawals in seconds to minutes, an exchange keeps some assets there.

A cold wallet keeps keys in an environment cut off from the network. It is safer, but moving funds takes people and time.

An exchange's design is a balance between how much sits in the hot wallet and how it is topped up from cold storage. The hot wallet was the target here, and the loss still reached $6.3 billion — a sign of the exchange's scale.

The company seal and the vault keeper

A transfer on a blockchain is legitimate if it carries a "signature by a private key". By analogy, the private key is a company's registered seal.

Lock the seal in a sturdy vault (an HSM, for example) so it cannot be taken out — and if someone gains the standing to hand the vault keeper a document and say "stamp this", the document gets stamped. If the keeper stamps without reading the contents, it gets stamped whether it is a "payment order" or a "power of attorney".

The analogy has limits. A real person reads before stamping; a signing system only applies the rules its designers wrote. When the rule was "look at amount and destination", a kind of document with neither falls outside the rule.

Three layers to protect: key, signature, business

"Protect the assets" splits into at least three separate questions.

LayerQuestionExample controlsIf it is broken
1 Key custodyCan the key be taken out?HSM, MPC, KMSThe key is stolen and the attacker signs on their own
2 Signing authorizationWhat may be signed?Policy engine, decoding what is signed, approval flowThe legitimate signing system produces signatures nobody wanted
3 Business authorizationIs the withdrawal legitimate as business?Destination allowlist, limits, independent approval, anomaly detectionThe signature looks fine but the movement of funds is not legitimate

Most discussion concentrates on layer 1. Key-protection design is mature, with standards such as NIST SP 800-57. But layer 1 alone does not protect layers 2 and 3. As here, huge sums can leave while it is unclear whether layer 1 was broken at all, as far as is disclosed.

What HSMs, MPC and KMS do, and do not do

MechanismRoleDoes not
HSM (dedicated tamper-resistant device)Keeps the key inside the device and signs thereJudge whether the contents of the request are legitimate; it serves whoever holds the privilege to call it
MPC (shared signing with split key)A breach of one place does not expose the whole keyIf enough participants agree to the same request it signs; whether the request is right is another matter
KMS (cloud key management)Key storage, access control, usage recordsA principal with IAM permission that calls the signing API gets a signature

What they share is that a key mechanism does not decide who may request a signature or what may be signed. That is layer 2's responsibility.

What is visible on-chain: a signature with no amount and no destination

This section concerns publicly available records anyone can check.

What can be confirmed

A transaction published on Etherscan, at 20:20:59 UTC on 29 October 2026, is in block 26,300,753 and has these features:

  • Transaction type 4 (the "set code" type of EIP-7702)
  • The sender is an address labeled as the attacker's; the recipient is the Binance hot wallet labeled "Binance 14"
  • It carries 50 authorizations, of which one is valid (nonce 18914809), with a single delegate address

The author fetched the same transaction from a public Ethereum RPC and checked these himself: type 4, 50 authorizations, chain ID 1, and one delegate address.

Author's observation: checking Binance 14's current code on the same RPC on 1 November 2026 returned empty (0x). That indicates no delegation is set now (it was removed or replaced), but I have not checked when or by whom it was removed.

What EIP-7702 is (what the specification says)

EIP-7702, "Set Code for EOAs", has the status Final. Normally an externally owned account (EOA) only signs with its key to send funds and has no program. EIP-7702 lets an EOA run the code of a chosen contract as its own. The specification's essentials:

  • The signature covers [chain_id, address, nonce], and does not include an amount or a destination
  • If the authorization is valid, the account's code is set to 0xef0100 || address (a marker meaning "defer to the code at this address")
  • From then on, calls to the account are executed by the delegated code, in the account's own context
  • A delegation that has been set is not rolled back even if execution of the transaction fails

The specification's Security Considerations say a poorly implemented delegate can let a malicious actor "take near complete control over a signer's EOA".

What can and cannot be said

Can be said (confirmed)Cannot be said
A record exists of an EIP-7702 delegation being set on Binance 14How the attacker obtained that signature
An authorization must be signed with the account's key (specification)Whether a key was taken, or the signing system was made to sign
A delegation signature does not contain an amount or a destination (specification)Whether Binance's signing system inspected this kind of signature (internal design is not public)

Analytics firm Elliptic assesses that the attacker "appears to have made Binance's own systems sign", and relays Binance's account that this delegation "did not pass through our normal approval controls". TRM Labs also says it "points to a compromise of Binance's hot wallet signing infrastructure". But these are analyses, not Binance's official finding of cause. Some experts, such as at SlowMist, keep key leakage open as a hypothesis.

The author's view: why a policy that looks only at amount and destination is not enough

What follows is the author's inference from published facts. It is not established fact.

If a withdrawal policy is built as "the amount is within the limit and the destination is on the allowlist", a signature that is not shaped like a transfer (one that changes how an account behaves) can fall entirely outside what the policy evaluates. If the policy does not distinguish "a transfer or not" and does not read the actual bytes to be signed, this hole opens.

Whether Binance's policy was like that is unknown. What designers can take away is the principle of restricting which kinds of signature are allowed. The teaching code below turns it into code.

Reference architecture: the withdrawal and signing pipeline

Note: the diagram below is a generic reference model for an exchange or payment system. It is not a reconstruction of Binance's internal design.

 [User]──withdrawal request──▶ [Withdrawal API] ──▶ [Policy engine] ──▶ [Signing service] ──▶ [Blockchain]
                                 authentication,      layers 2 and 3        layer 1 (HSM/MPC/KMS)
                                 idempotency key      · decode the actual    the key never leaves
                                                        bytes to be signed
                                                      · refuse non-transfers
                                                      · reserve limits atomically
                                                      · verify approval (2 independent people)
                                  │
        [DevOps workstation] ─ ─ ✕ ─ ─ ▶ no direct line to the production signing path (people only see the approval screen)
                                  │
                                  ▼
                        [Audit log (append-only)] ──▶ [Anomaly detection / emergency stop]

Threat model: from account compromise to unauthorized withdrawal

StageWhat happensLayer that stops it
1. FootholdA developer workstation, CI or container is compromisedWorkstation separation, short-lived credentials, network separation
2. Lateral movementThe compromised principal reaches privileges that can call the signing serviceLeast-privilege IAM and workload identity; restricting who can call signing
3. Signing requestThe attacker asks for a signatureLayer 2: inspect the actual bytes, refuse non-transfers by default
4. Movement of fundsIf signed, assets moveLayer 3: destination allowlist, limits, independent approval, cooling-off
5. ExitAssets leave and are dispersedAnomaly detection, emergency stop, coordination with issuers (freezing)

From DevOps workstation to production: the trust boundary

Update #2 revised the account, and the real route is unknown. If the path in update #1, "DevOps workstation → service container → withdrawal", were accurate, it would illustrate a typical risk of a person's machine being too close to production assets. In general, separate these:

  • Development and operations workstations do not connect directly to the production signing path. Needed operations go through an approval flow (change management)
  • A service's privileges (workload identity) are limited to that service's role. If a container can instruct withdrawals, whoever takes over the container gets that same power
  • A person's long-lived credentials do not work against the production signing API. Use short-lived tokens and per-action approval

Teaching code: a withdrawal policy engine that sits before signing

Here is a TypeScript implementation of layers 2 and 3. The complete code and tests are in this site's repository at tests/unit/fixtures/withdrawal-policy.ts and tests/unit/withdrawal-policy.test.ts, and run in CI all the time.

Limits. This is an educational reference implementation. A real asset-management system needs a persistent database, authentication to the signing service, key operations, audit and incident handling, which this code does not replace.

Design approach

RequirementImplementation here
Amount type with explicit currency and minimum unitMoney { asset, minor: bigint }. Strings like "0.1" convert to integers without rounding; too many decimals are rejected
Avoid floating-point errorAmounts are always integers (bigint); number is not used
Judge the actual bytes to be signedDecode the bytes to decide the kind, not the caller's description
Refuse non-transfer signaturesDelegations (type 4), approvals and unknown kinds are refused by default
Refuse bad destinationsAllowlist plus a cooling-off period after a destination is added
Approval binding, expiry, replay protectionAn approval is bound to the digest of the request and expires. A request id can reserve only once, so reusing an approved request is refused
Separation of dutiesThe requester's own approval is invalid; two different people and two different roles are required
Atomic limit updateThe check and the update are one indivisible operation
IdempotencyThe same idempotency key returns the same decision and does not reserve twice; different content is rejected
Fail closedUnexpected errors turn into a denial
AuditabilityEvery decision goes to an append-only log
Emergency stopA circuit breaker (when open, deny everything). It is checked before the stored idempotent decision, so a replay of an already-allowed request is stopped too

Decode the actual bytes to be signed

export interface SigningPayload {
  readonly txType: number; // EIP-2718 transaction type. 0x04 is EIP-7702
  readonly to: string;
  readonly valueWei: bigint;
  readonly data: string; // hex calldata. "0x" for a plain ETH transfer
}

export type Intent =
  | { readonly op: "native_transfer"; readonly recipient: string; readonly amount: bigint }
  | { readonly op: "erc20_transfer"; readonly token: string; readonly recipient: string; readonly amount: bigint }
  | { readonly op: "delegation" | "approval" | "unknown" };

const SELECTOR = {
  transfer: "0xa9059cbb", // transfer(address,uint256)
  approve: "0x095ea7b3", // approve(address,uint256)
  setApprovalForAll: "0xa22cb465", // setApprovalForAll(address,bool)
} as const;

/** Read the bytes, not the caller's label. Anything unreadable is "unknown". */
export function decodeIntent(p: SigningPayload): Intent {
  if (p.txType === 0x04) return { op: "delegation" }; // a signature that hands over the account's code
  const data = p.data.toLowerCase();
  if (data === "0x") return { op: "native_transfer", recipient: p.to.toLowerCase(), amount: p.valueWei };
  if (p.valueWei !== BigInt(0)) return { op: "unknown" };
  const selector = data.slice(0, 10);
  if (selector === SELECTOR.approve || selector === SELECTOR.setApprovalForAll) return { op: "approval" };
  if (selector === SELECTOR.transfer && data.length === 10 + 64 + 64) {
    return {
      op: "erc20_transfer",
      token: p.to.toLowerCase(),
      recipient: "0x" + data.slice(34, 74),
      amount: BigInt("0x" + data.slice(74, 138)),
    };
  }
  return { op: "unknown" };
}

0xa9059cbb, 0x095ea7b3 and 0xa22cb465 are the function selectors of ERC-20 transfer(address,uint256), approve(address,uint256) and setApprovalForAll(address,bool), which the author confirmed against a public signature directory.

The point is to explicitly enumerate the allowed kinds and refuse everything else. A "ban the dangerous ones" approach (a blocklist) lets kinds of signature you have never heard of through.

Order of checks, and matching "claim" against "reality"

// Excerpt: WithdrawalPolicy.#decide
if (this.#circuitOpen) return audit(deny("circuit_open"));

// Judge the thing that will actually be signed, not the claim.
const intent = decodeIntent(req.payload);
const expectedToken = this.cfg.tokenContracts[asset]?.toLowerCase();
const kindOk =
  (intent.op === "native_transfer" && asset === "ETH") ||
  (intent.op === "erc20_transfer" && intent.token === expectedToken);
if (!kindOk) return audit(deny("operation_not_permitted"));
if (intent.recipient !== req.destination.toLowerCase() || intent.amount !== minor) {
  return audit(deny("payload_mismatch"));
}
// ...allowlist, cooling-off, per-transaction limit, approval verification...
// Last, check and update the limit as ONE indivisible operation:
const reservationId = `rsv_${req.id}`;
const slot = await this.store.tryReserve(reservationId, req.accountId, asset, minor, this.cfg.dailyLimit[asset], now);
if (slot === "duplicate") return audit(deny("request_already_used"));
if (slot === "limit") return audit(deny("daily_limit"));
return audit({ kind: "allow", reservationId });

payload_mismatch checks that the amount and destination the request claims match what is actually signed. Not trusting the claim is the basic stance of layer 2.

Bind an approval to one specific request

export function requestDigest(r: WithdrawalRequest): string {
  const p = r.payload;
  const canonical = JSON.stringify([
    r.id, r.accountId, r.amount.asset, r.amount.minor.toString(), r.destination,
    p.txType, p.to.toLowerCase(), p.valueWei.toString(), p.data.toLowerCase(),
  ]);
  return createHash("sha256").update(canonical).digest("hex");
}

What an approver agrees to is "this request". If the approval is bound to the digest, using it on another request (replay) is invalid. On top of that it has an expiry, the requester's own approval is invalid, and it requires two different people in two different roles.

A race condition: "check, then update" breaks

A limit check is sometimes written like this:

// Bad example (RacyStore): read → wait → decide → write
const used = this.#used.get(key) ?? BigInt(0); // 1. read
await sleep(5);                                // 2. wait on a round trip to the DB
if (used + amount > limit) return "limit";     // 3. decide on a stale value
this.#used.set(key, used + amount);            // 4. write
return "reserved";

Another request slipping in between the read and the write is called a TOCTOU (time-of-check to time-of-use) gap. Take concrete numbers: a daily limit of 10 ETH, and 50 simultaneous requests of 0.9 ETH each. The right answer is that it stops at 11 (10 ÷ 0.9, rounded down).

ImplementationRequests let through out of 50 concurrent
Check and update separated (the bad example above)50 (the limit blown through)
Check and update as one indivisible operation11 (stops at the limit, correctly)

These are values the author measured in the tests. All of them got through because all 50 decided on a stale value of "nobody has used any yet".

In a real database you achieve this with a conditional update such as UPDATE ... SET used = used + $amount WHERE used + $amount <= $limit (judging success by the number of rows updated), or with a row lock. The in-memory implementation in the teaching code shows the same property by "reading and writing without an await in between". The reservation also needs a unique constraint per request id; the teaching code refuses a second reservation for the same request id as request_already_used, so resubmitting an approved request under a different idempotency key cannot spend the limit twice.

Test results

npx vitest run tests/unit/withdrawal-policy.test.ts ended with all 25 tests passing in the author's environment, and tsc type checking and ESLint passed too. What is verified:

  • Amount parsing (too many decimals, negatives, zero and exponent notation are rejected)
  • Decoding of signatures (transfer, delegation, approval, unknown). Calls with ETH attached, and calldata that is truncated or has extra bytes, cannot be read exactly and are refused. Address case is ignored. A native-transfer signature cannot satisfy a USDT request
  • A small withdrawal to an allowlisted destination is allowed (ETH and USDT)
  • Delegation, approval and fake-token signatures are refused even when the request looks harmless
  • A request whose claimed destination and amount differ from what is actually signed is refused
  • Unknown destinations and just-added (cooling-off) destinations are refused
  • Over-limit requests, and requests above the approval threshold without approval, are refused
  • Expired approvals, approvals reused on another request (changing the destination, amount or account invalidates them), self-approval, same-role-only approval, duplicated approvers and one person holding both roles are refused
  • Spending an approved request twice by resubmitting it under a new idempotency key is refused (request_already_used)
  • Exact boundaries (cooling-off, per-transaction limit, approval threshold, approval expiry) and the rolling 24-hour window (usable up to exactly the limit, released after 24 hours)
  • Idempotency: a retried request reserves once; different content under the same key yields idempotency_conflict. A transient failure is not remembered, so the same key can be retried
  • 50 concurrent requests do not exceed the limit (atomic reservation) / the implementation that separates check and update does
  • The circuit breaker's deny-all (a replay of an already-allowed request is stopped too) and the logging of decisions (immutable). The breaker opens even if the audit store is down
  • A store failure becomes a denial (fail closed). An audit-write failure after the reservation is also a denial, but with no compensation step the reservation is not released (pinned as a known limit)

The invariants were not weakened, and no test was disabled, to make them pass.

What this code does not show

  • Connection to a real signing service, key operations, network authentication
  • Limit consistency across multiple nodes with persistence
  • Verification of the EIP-7702 signature itself (this code judges the request before it is signed)
  • A statistical model for anomaly detection (threshold design)
  • Authenticating approvers. approverId and role are assumed to be verified input; verifying the approval signature itself is not included
  • Approval on the daily total. The approval threshold is per request, so splitting a withdrawal into smaller ones avoids it; a real system also applies a threshold to the running total
  • Compensation. If the audit write fails after the reservation, the code returns a denial but the reservation is not released
  • A denial is also stored under its idempotency key. Send a corrected request under a new idempotency key

What a Proof of Reserves can confirm

In update #3 Binance showed a Proof of Reserves snapshot as of 00:00 UTC on 31 October and said a full proof including zero-knowledge proofs would be published by 3 November (UTC).

As the author understands it, a PoR shows whether assets matching customers' deposits exist at a point in time. What it does not show matters just as much.

What a PoR can confirmWhat a PoR cannot confirm
Whether holdings cover the sum of customer balances, at a point in timeWhether key and signing management is safe
That some of the holdings sit at publicly visible addressesHow assets were lost, and whether it will recur
(With zero-knowledge proofs) that totals reconcile without revealing each customer's balanceWhether the liabilities (what is owed to customers) are all included (design-dependent)

A PoR answers "is there enough now?", not "is it safely guarded?" Not confusing the two is basic to evaluating an exchange.

For executives: why money leaves even when keys are safe, and the order to decide

For non-engineers, what this incident suggests deciding.

Three questions

  1. Who looks after the vault key, and how far? Key custody (layer 1) can be protected by specialist products and procedures, where many companies already invest.
  2. Who decides the rule for "what may be stamped"? That is layer 2. Is the rule "just amount and destination", or written by someone who has since left?
  3. When money goes out, is there a human eye and a way to stop it? Layer 3. For large withdrawals the basics are approval by two or more independent people, and automatic stop (a circuit breaker) on anomalies.

Setting priorities

PriorityActionPurpose
HighInventory credentials and privileges used to move production funds; remove anything a person's workstation can use to reach the production signing pathGuard the entrance to layer 2
HighSet limits and the threshold for independent approval on withdrawals and transfers. If you run payments or transfers, confirm the limit holds under concurrencyLayer 3
MediumKeep audit logs of signing, approval and configuration changes where they cannot be tampered withAfterward verification
MediumDefine and rehearse the emergency-stop procedureStop the damage from growing
LowRead published post-mortems and compare against your own setupLearning

For a business that moves money, designing "stopping" as a feature is the executive decision. A service stopping is a loss, but smaller than being unable to stop while assets leave — and that judgment has to be made in peacetime.

Checklists

Design and implementation

  • The signing service decodes the actual bytes to be signed and does not rely on the caller's description
  • The allowed kinds of signature are enumerated, and delegations, approvals, authority transfers and unknown kinds are refused by default
  • Destinations are allowlisted, with a cooling-off period after one is added
  • An approval is bound to a specific request, expires, and cannot be given by the requester
  • The limit "check and update" is atomic, with a concurrency test
  • Idempotency keys are handled server-side, and different content under the same key is rejected
  • Unexpected errors become denials (fail closed)
  • Amounts are held as integers in the minimum unit (no floating point)

Operations and organization

  • A person's workstation has no direct path to the production signing path
  • A service's privileges (workload identity) are limited to its role
  • Decisions, approvals and configuration changes leave an audit log that is append-only and kept elsewhere
  • An emergency-stop procedure exists and has been rehearsed
  • Large withdrawals need multiple independent approvals (separation of duties)
  • On-chain and off-chain balances are reconciled automatically

Conclusion and what to watch next

  • What can be said as fact: hot wallets were compromised and about US$6.3 billion left. About $3B is frozen, 90% has been replenished (with Binance's own funds), and no recovery has been published. Withdrawals are suspended, with a phased reopening planned for 1 November. On-chain there is a record of an EIP-7702 delegation set on Binance 14.
  • What cannot yet be said: the root cause, whether keys leaked, how the attacker obtained the delegation signatures, who was responsible (the analytics firms' assessment is a hypothesis).
  • The technical lesson: protecting the private key (layer 1) does not replace signing authorization (layer 2) and business authorization (layer 3). A design that decides what may be signed from the actual bytes and refuses by default is needed separately from key protection.

To watch: Binance's technical post-mortem (the cause, and the "additional points of breach" in update #2), the full Proof of Reserves (due 3 November), the handling of frozen assets, and the situation after withdrawals reopen.

If you want your transfer, payment or fund-movement design reviewed

The author has led the design and implementation of the reliability layer of a payment platform — idempotency, consistency and prevention of double charges. From the viewpoint of this article, a design review of your backend, payment APIs, cloud privileges and the controls on moving funds is something I can do.

What I can and cannot do, up front:

  • I can: review the design of transfer and payment APIs, approval flows, limits and idempotency, cloud IAM and service privileges, and audit logging and anomaly detection, with a prioritized improvement plan and a design for concurrency and failure-path tests
  • I cannot: provide specialist audits of crypto custody, evaluation of key management (operating HSMs or MPC), or incident forensics. Please consult specialist providers for those
  • I cannot promise you will be "completely secure". I report what was found and what was not examined, as it is

See the scope and pricing through the button below.

Frequently asked questions

Is the Binance loss 6.3 billion yen?
No. Binance's update #2 says 'approximately $6.3B USD', so about 6.3 billion US dollars. The yen figure moves with the exchange rate. Analytics firms put it at about $6.36 billion at the prices when it was taken (TRM Labs) and about $6.43 billion (Elliptic); they differ in the number of chains counted and the time of the snapshot.
Were Binance's private keys leaked?
It is not settled. Binance says it has 'found no evidence' that wallet private keys were leaked 'at this stage', which is not a statement that they were not. Elliptic's analysis is that the attacker appears to have made Binance's own systems sign. As of 1 November 2026 no technical post-mortem has been published.
Has the roughly $3 billion that was frozen been returned?
No. Frozen means issuers such as Tether and Circle made the tokens at the relevant addresses immovable; it does not mean the funds came back to Binance (recovery). No recovered amount has been published. The 90% replenishment is Binance buying back assets from its own funds, the SAFU and a futures insurance fund — also separate from recovery. Elliptic says assets stolen on Bitcoin, the XRP Ledger, Solana and NEAR have not been frozen.
Wouldn't an HSM or MPC have prevented it?
HSMs and MPC prevent a key from being taken out; they do not stop a signing request arriving through a legitimate path from being honored. An EIP-7702 delegation signature can hand an account's behavior to other code without containing an amount or a destination. You need a policy layer that inspects what is being signed, plus separation of duties. How Binance protected its keys has not been disclosed.
Have Binance withdrawals resumed?
Not as of 01:00 JST on 1 November 2026. Update #3 (31 October) says a phased reopening is planned for Sunday 1 November. Deposits are described as operating normally in the official updates from 30 October onward. Binance Japan was reported to have paused only crypto withdrawals, with deposits, trading and yen deposits and withdrawals normal.
If I run payments or transfers myself, what should I check first?
Five things: whether the signing service decodes the actual bytes to be signed instead of trusting the caller's description; whether it refuses non-transfer signatures (approvals, delegations, authority changes) by default; whether approvals are bound to a specific request and expire; whether limit checks and updates are atomic; and whether any path from a person's workstation reaches production signing.

References

友田

友田 陽大

Developer of a METI Minister's Award–winning product. With TypeScript + Python + AWS, I deliver SaaS, industry DX, and production-grade generative AI (RAG) end to end — from requirements to infrastructure and operations — single-handedly.

Before you hold real customer data

Web app & SaaS security audit — authorization, tenant isolation and config, verified in the code

Beyond what tools catch, the design gap — who may touch which data — checked in the source code and configuration, with a prioritized fix plan. Not only Next.js / Supabase: web apps on Rails, Laravel, Django, Go and others, plus AWS / GCP / Vercel configuration. We never call anything “completely secure.”

Available for both project-based (contract) and advisory engagements. Start with a free 30-minute consult.

Also worth reading