Trustodian

Custody security: best practices

Hardening the withdrawal and signing pipeline for crypto exchanges and custodians, based on lessons from the 2025 Bybit and 2026 Bitget incidents. Written for teams integrating the Trustodian API and SDK into their own stack.

Core principle

Protect the intent, not just the key.

MPC, multisig, and HSMs protect private keys. They do not, on their own, verify that a transaction is one you actually meant to send.

Why this exists

Both attacks produced valid signatures without stealing a key

In both the Bybit (February 2025, about $1.5B) and Bitget (September 2026, about $387.5M) incidents, attackers did not steal private keys. Instead, they got the operator's own signing system to produce valid signatures for transfers the operator never intended to send.

Bybit

The multisig signing interface was tampered with, so human signers saw one transaction and approved another.

Bitget

A vulnerability in a third-party security product gave attackers internal credentials. They compromised the wallet backend, forged transaction data, and drove the normal authorization flow.

The shared failure: one signing pipeline trusted one upstream source of truth. Once that source was compromised, the signing technology did exactly what it was built to do, on forged instructions.

Threat model

Assume any single component can be fully compromised at any time

ComponentExample compromisePrimary control
Withdrawal backendForged transaction data sent to signersIndependent verification at each signer (section 1)
Admin or service credentialsStolen via vendor flaw or phishingSeparate trust roots, least privilege (sections 2, 8)
Signing UIDisplays a different transaction than the one signedClear signing on independent devices (section 6)
Third-party toolingSecurity or monitoring agent with broad accessVendor isolation (section 7)
A single signer nodeMalicious or buggy policyThreshold across independently run nodes (section 2)

Design goal: no single compromise can move funds beyond a small, pre-defined, bounded amount.

Reference architecture

Three independent policy engines, three signers, one direct halt

User device signs request
API gateway
→
User ledger
Tx builder
→
Policy engine A
Policy engine B
Policy engine C
→
Signer A
Signer B
Signer C
→
Broadcast
Reconciliation monitor (halts signers directly)

Dashed boxes are read or control paths that bypass the transaction builder: each reads the ledger independently, and the reconciliation monitor can halt every signer without going through the backend.

  • Every signer has its own policy engine that validates independently.
  • Policy engines read the ledger through separate paths, not through the tx builder.
  • The reconciliation monitor can halt signing directly, without going through the backend.
Section 1

Verify intent at the signer

The signer must never sign something just because the backend asked. Each signing party (every MPC node, multisig co-signer, or HSM policy layer) should independently confirm all of the following:

  • A matching withdrawal request exists in the user ledger (same user, asset, amount, destination).
  • The user's balance covered the amount at request time.
  • The request is signed by the user's device key and the signature is valid (end-to-end request signing).
  • The destination is allowed for this wallet tier (section 3).
  • The amount is within per-transaction and rolling velocity limits (section 4).
  • The request has not already been signed (replay and double-spend protection).
  • The raw transaction the signer is about to sign actually decodes to the validated intent: no hidden calls, approvals, or delegatecalls.

Example policy check (pseudocode)

def approve_signing(raw_tx, request):
    intent = decode(raw_tx)                          # decode what will actually be signed
    assert verify_user_sig(request)                  # request came from the user's device
    record = ledger_readonly.get(request.id)         # independent read, not via backend
    assert record and record.matches(intent)         # ledger agrees with the tx
    assert not already_signed(request.id)            # no replay
    assert destination_allowed(intent, wallet_tier)  # tier flow rules
    assert within_velocity_limits(intent)            # per-tx and rolling caps
    assert not circuit_breaker_tripped()             # global halt
    return True

If any check fails, the signer refuses and raises an alert.

Section 2

Separate trust roots

Multiple signers add little if they all trust the same upstream system.

  • Run each signer and its policy engine on separate infrastructure, ideally separate cloud accounts or providers.
  • Have different teams operate different signers, with no shared admin credentials.
  • Give each policy engine its own read path to the ledger: a read replica, signed ledger snapshots, or an independent reconciliation service.
  • Where practical, use different software implementations for policy checks so one bug or one exploit does not affect all signers.
  • Make sure no single person, credential, or service can reach a threshold of signers.
Section 3

Wallet tiering and flow restrictions

Keep the amount at risk small, and restrict where each tier can send.

TierShare of assets (example)Allowed destinationsSigning
HotAs small as operations allowUser withdrawals within limitsAutomated, policy-gated
WarmBuffer for refilling hotOnly the operator's own hot walletsPolicy-gated plus human approval above threshold
ColdMajority of assetsOnly the operator's own warm walletsOffline, multi-party, human approval, time delay
  • Enforce flow rules at the signer, and on-chain where possible (smart contract wallets with allowlists).
  • Refill hot wallets in small, frequent batches rather than large transfers.
  • Size hot balances from actual withdrawal data, and review regularly.
Section 4

Velocity limits and time delays

  • Per-transaction caps per asset and per tier.
  • Rolling window caps (for example, per 10 minutes and per hour) across all transactions.
  • Per-destination caps, especially for new or rarely used addresses.
  • Time delays on large transfers, with a cancellation window monitored by a separate team.
  • Limits must be enforced inside each signer's policy engine, not only in the backend.
Section 5

Circuit breakers

Detection only helps if it triggers action automatically.

  • Continuous reconciliation of on-chain balances against the internal ledger.
  • Automatic signing halt when reconciliation fails, velocity limits are hit, or anomalous destinations appear.
  • The halt signal goes directly to signers through an independent channel, not through the backend.
  • Resuming signing requires multi-party human approval.
  • Target: halt within seconds, not minutes. In the Bitget incident, a discrepancy was flagged about seven minutes after the first large transfer, yet on-chain outflows continued for hours.
Section 6

Human approval and clear signing

For transfers above threshold and all cold or warm movements:

  • Approvers verify the decoded transaction on a dedicated device (hardware wallet or air-gapped signer), never only on a web UI.
  • Use clear signing: the device shows destination, amount, and contract call in human-readable form.
  • Require approvers from different teams, using different devices and networks.
  • Serve signing UIs from pinned, integrity-checked builds (subresource integrity, reproducible builds, no dynamic third-party scripts).
  • Compare the transaction hash on at least two independent devices before approving.
Section 7

Third-party and vendor risk

The Bitget entry point was reportedly a flaw in a third-party security product.

  • Keep an inventory of every vendor tool with access to production.
  • No vendor tool should have a network path to signing infrastructure.
  • Give agents (EDR, monitoring, backup) least privilege; avoid domain-admin-style credentials.
  • Patch vendor software quickly, and subscribe to vendor security advisories.
  • Isolate vendor management consoles on separate networks with separate credentials.
  • Assess vendors for secure development practices and incident history.
Section 8

Access control and infrastructure

  • Network-segment signing infrastructure; allow only required, authenticated connections.
  • Hardware-backed MFA (FIDO2 keys) for all privileged access.
  • Just-in-time, time-bound privileged access with approval and logging.
  • No standing production access for developers.
  • Signed and reviewed deployments for backend, policy engines, and signing UIs.
  • Tamper-evident, centralized audit logs stored outside the production trust domain.
  • Routine credential rotation, plus immediate rotation after any suspected compromise.
Section 9

Incident response

Prepare before you need it.

01

Halt

all signing (circuit breaker) and pause withdrawals.

02

Contain

revoke credentials, isolate affected systems, preserve forensic evidence.

03

Trace

work with on-chain analytics firms to label attacker addresses.

04

Freeze

contact stablecoin issuers, other exchanges, and bridges using pre-established contacts.

05

Communicate

publish an accurate, timely notice to users.

06

Recover

consider bounties for freezing and recovering funds.

07

Restore

resume withdrawals in phases only after the root cause is fixed and verified.

08

Report

publish a post-mortem with the root cause and remediation.

  • Maintain a user protection fund or insurance sized to realistic worst-case hot and warm exposure.
  • Run tabletop exercises at least twice a year.
Section 10

Testing and assurance

  • Red-team exercises that assume the backend is fully compromised and try to get a signature.
  • Chaos tests: inject forged transactions and confirm signers refuse them.
  • Test circuit breakers end to end, including halt latency.
  • Independent audits of policy engines, signing UIs, and key management.
  • Regular proof of reserves with liabilities, audited by a third party.
Checklist

Fifteen controls to tick off

Signing and intent

  • Every signer independently validates the decoded transaction against the ledger
  • Withdrawal requests are signed end to end from the user's device
  • Replay protection on signing requests

Trust separation

  • Signers run on separate infrastructure with separate operators
  • Policy engines have independent read paths to the ledger
  • No single credential can reach a threshold of signers

Limits

  • Wallet tier flow rules enforced at signer level
  • Per-transaction and rolling velocity caps in every signer
  • Time delays on large transfers with a monitored cancel window

Detection and response

  • Automated reconciliation with direct signing halt
  • Incident runbook tested in the last six months
  • Pre-established contacts with issuers and analytics firms

People and vendors

  • Clear signing on dedicated devices for human approvals
  • Vendor tools have no path to signing infrastructure
  • Hardware MFA and just-in-time access for all privileged roles
For end users

You can't stop an exchange being hacked, but you can limit your exposure

  • Keep only what you are actively trading on exchanges.
  • Store long-term holdings in a hardware wallet you control.
  • Spread funds across more than one platform.
  • Prefer platforms with audited proof of reserves and a meaningful protection fund.
  • Enable withdrawal allowlists and hardware 2FA. These protect against account takeover, not a platform-level breach.
Further reading

Sources for the incident details above

Suggestions and corrections are welcome. Email [email protected] and include sources for any incident details.

Build on it

Trustodian enforces the quorum on-chain. Your integration should enforce the intent.

The SDK gives you per-key scopes, IP whitelists, spending limits, business hours, and address-book whitelisting. Pair them with the controls above so no single compromised system can produce a signature you didn't intend.