Back to blogs
Written by
Patrick Collins
Published on
May 12, 2026

Blind Signing - Solved?

Blind signing drained $1.5B from Bybit. Clear Signing launches today as the open standard to fix it — here's what Cyfrin shipped and where the work goes next.

Table of Contents

Blind Signing - Solved?

Today, Clear Signing — an open standard for making Ethereum transactions readable to the humans who authorize them — moves under the Ethereum Foundation's Trillion Dollar Security Initiative as its neutral steward. The launch ships an updated ERC-7730, an EF-hosted registry mirrorable by anyone, an ERC-8176 attestation framework, the Cyfrin-authored ERC-8213 bytes-level fallback, and developer libraries from a multi-vendor working group.

Cyfrin is one of the contributors. This post is what we built for the launch, why this problem has been a priority for us, and where we go from here.

What shipped today

The release isn't a single project — it's four pieces of infrastructure that work together:

  1. ERC-7730 and a neutral registry. Updated standard (spec) plus the EF-hosted registry — a single source of truth for the human-readable description of any clear-signed contract, copyable and self-hostable by anyone.
  2. ERC-8176 attestations. A framework — built on the Ethereum Attestation Service — for independent auditors to attest that a descriptor faithfully represents the contract it describes. Wallets decide whose attestations they trust.
  3. ERC-8213 — bytes-level fallback. A separate Cyfrin-authored standard for short cryptographic fingerprints of exactly what's about to be signed, for the cases ERC-7730 can't reach (custom packed encodings, brand-new contracts, system-level messages). erc8213.eth.limo is our teaching site.
  4. Developer libraries. Official Rust and TypeScript SDKs from the working group, plus Cyfrin's open-source clearsig for Python — covering ERC-7730 translation, ERC-8176 descriptor hashing, ERC-8213 digests, and Safe-specific signing.

Why this matters

In February 2025, Bybit's Ethereum cold wallet was drained for roughly $1.5 billion — at the time, the largest cryptocurrency theft on record. The attackers didn't break any cryptography. They didn't bypass any signatures. Multiple authorized signers, holding hardware wallets, approved the transaction that moved the funds. They just didn't realize what they were approving.

Five months earlier, Radiant Capital lost roughly $50 million in a structurally identical incident: hardware-wallet signers clicked "approve" on what their front-end claimed was a routine multisig operation, while their devices actually authorized a delegatecall handing the protocol's logic to an attacker. More recently, Drift Protocol joined the same list.

Different protocols. Different timelines. The same root cause: people authorized transactions they couldn't actually read.

This pattern has a name: blind signing — approving a transaction whose contents you can't verify, on the trust that whatever showed it to you wasn't lying. Hardware wallets were supposed to be the answer; without descriptors, they fall back to hex and the problem persists on a more trustworthy screen.

The working group's slogan is the cleanest summary of the goal: What You See Is What You Sign (WYSIWYS). Until that is the default, and blind signing is the exception rather than the norm, the last line of defense — the human reviewing the transaction — does not hold.

What a hardware wallet actually shows you

When you authorize a transaction from a hardware wallet, the device receives a hex string — the calldata — and asks you to confirm it. In the worst case, that is all you see:

0x6a76120200000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084617ba037000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000f42400000000000000000000000009467919138e36f0252886519f34a0f8016ddb3a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Reading that requires you to:

  1. Parse the four-byte function selector
  2. Look up the function name from the contract's ABI
  3. Decode each parameter against the ABI types
  4. Resolve tokens, addresses, and ENS names referenced
  5. Reason about what the call will actually do given the contract's state

A skilled engineer can do all of this with tools, given time, at a workstation. A multisig signer, under time pressure, on a three-line OLED display, cannot.

The industry's first response was to stop showing hex to humans and show "Send 100 USDC to vitalik.eth" instead. Making that version actually safe — rather than merely friendlier — is harder than it looks.

Why decoding the ABI alone is not enough

You might think the ABI solves the problem. Given the ABI, you can decode the bytes above into execTransaction(0x87870Bca..., 0, 0x617ba037..., 0, ...) and display each parameter. Two reasons that's still not enough.

Function names lie. The ABI tells you a function is called transfer. It doesn't tell you what transfer actually does. Solidity lets the developer name a function anything. Nothing stops a contract from naming a withdrawal function deposit, a malicious upgrade function pause, or a fund-extraction routine claimRewards. If your wallet trusts the function name to derive user intent, anyone deploying a contract can choose any intent for your wallet to display.

Parameters need context to be meaningful. A uint256 amount is just a number. Wei? Micro-USDC with 6 decimals? A timestamp? A duration in seconds? A basis-point fee? Without protocol-specific knowledge baked in, "amount: 1000000" is not actually human-readable — it's just a less alarming version of hex. ABIs give you types, not semantics.

Decoding the ABI gives you a more readable version of the hex. It does not give you a truthful version. That distinction is what gets people robbed.

For a deeper walkthrough of why this is hard, Patrick recorded an explainer a while back: Hardware wallet clear signing.

ERC-7730: descriptors instead of raw ABIs

ERC-7730 — originated by Ledger and matured into a multi-vendor standard — addresses both problems above. It defines a JSON format (a descriptor) that maps a contract's functions to human-readable intents and field-rendering instructions. A USDC descriptor's transfer entry:

"transfer(address to,uint256 value)": {
  "intent": "Send",
  "fields": [
    { "path": "to",    "label": "To",     "format": "addressName" },
    { "path": "value", "label": "Amount", "format": "tokenAmount" }
  ]
}

A wallet with this descriptor knows: when you call transfer on USDC, show "Send {amount} to {recipient}", format the amount with six decimals and the USDC ticker, resolve the recipient to an ENS name if available.

Descriptors are curated by the protocol team, reviewed by third-party auditors, and collected in a neutral registry hosted by the EF. Wallets pull from the registry and decide whose attestations they trust. The function-name and parameter-context problems are addressed.

Showing clearsig translate

Cyfrin's first contribution is clearsig — an open-source Python CLI and library that implements ERC-7730 translation, ERC-8176 descriptor hashing, ERC-8213 digests, and Safe-specific hashing. It complements the official TypeScript and Rust libraries shipping in today's launch.

The cleanest way to feel what clear signing buys you is to run a real transaction through it. Here is a Safe execTransaction wrapping an Aave v3 supply of 1 USDC — the same nested shape as the Bybit attack.

Without clear signing, the hardware wallet sees:

0x6a76120200000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084617ba037000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000f42400000000000000000000000009467919138e36f0252886519f34a0f8016ddb3a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Same bytes, decoded through ERC-7730:

clearsig translate \
  0x6a76120200000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084617ba037000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000f42400000000000000000000000009467919138e36f0252886519f34a0f8016ddb3a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \
  --to 0x41675C099F32341bf84BFc5382aF534df5C7461a \
  --chain-id 1 \
  --from-address 0x9467919138E36f0252886519f34a0f8016dDb3a3
Intent: sign multisig operation (Safe{Wallet})
Function: execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)

  Operation type: Call
  From Safe: 0x41675C099F32341bf84BFc5382aF534df5C7461a
  Execution signer: 0x9467919138E36f0252886519f34a0f8016dDb3a3
  Transaction: Supply (Aave DAO)
  -> supply(address,uint256,address,uint16)
  Amount to supply: 1000000
  Collateral recipient: 0x9467919138e36f0252886519f34a0f8016ddb3a3
  Referral Code: 0
  Gas amount: 0
  Gas price: 0
  Gas receiver: 0x0000000000000000000000000000000000000000
  Safe Tx Gas: 0
  Signatures: 0x

The outer execTransaction is identified as a Safe multisig operation; the inner calldata is recognized as Aave's supply, with the amount and recipient pulled out by name. A signer looking at the second version can tell what they are approving. A signer looking at the first version cannot.

clearsig translate runs this offline against a local copy of the registry, so signers — and auditors — can verify on an isolated device before approving on the hardware wallet itself. Install it with whichever Python tool you prefer:

uv tool install clearsig          # or pipx / pip
clearsig translate <calldata> --to <address> --chain-id <N>

The first run auto-downloads the ERC-7730 registry. Point at a local checkout — for instance a PR branch under review — with ERC7730_REGISTRY_PATH=/path/to/registry.

When ERC-7730 cannot reach: ERC-8213

Descriptors only exist for contracts someone has authored a descriptor for. For everything else — brand-new contracts, custom packed encodings (Safe MultiSend, Uniswap Universal Router), zkSync L1 ↔ L2 system messages — there is no descriptor to render. For some of these there never will be, because the encoding does not fit the selector-plus-ABI model ERC-7730 assumes.

ERC-8213, which Cyfrin authored, exists for those cases. It defines short, reproducible cryptographic fingerprints of exactly what is about to be signed. The simplest is the calldata digest:

keccak256(uint256(len(calldata)) || calldata)

A length-prefixed hash of the exact bytes that will hit the contract. The use case is cross-device verification: before signing on a hardware wallet, the signer computes the same digest on an isolated machine — a clean laptop, an offline phone, a second hardware wallet. If the digest the wallet is about to sign matches the digest computed independently, the bytes are correct. If they don't, something has been substituted between the front-end and the device — exactly the class of attack that drained Bybit and Radiant.

ERC-8213 covers calldata digests, EIP-712 domain / message / final hashes, and Safe-specific signing hashes. It doesn't try to make the data human-readable — that's ERC-7730's role. It makes it verifiable, which is a weaker but always-applicable guarantee.

We built erc8213.eth.limo as a teaching site for using these digests on hardware wallets — it also tracks which wallets have implemented the standard. The first is Keycard Shell, which displays the calldata digest alongside the ABI-decoded view during signing, so a security-conscious signer can verify in a single hash instead of paging through hex. An older walkthrough of the same pattern for Safe wallets, before ERC-8213 was formalized, is at hardware-wallet-multi-sig-signature-verification-how.

What's still open

Two real limitations remain, and we don't want to oversell what shipped today.

Descriptors aren't instant. If a contract isn't in the registry yet, there's no human-readable rendering — you're back to ABI decoding or hex. Getting included takes a PR, an auditor review, and ecosystem buy-in. ERC-8213 is the fallback for that window (and for contracts that never fit the ERC-7730 model at all), but it isn't a replacement for descriptor coverage.

Air-gapped wallets need a transport story. Air-gapping a hardware wallet — keeping it physically disconnected from the host — is one of the strongest security postures available, but it makes pulling a large, frequently-updated registry hard. The working group is building a Wire Protocol to address this; it isn't live yet. Until it is, descriptor support on air-gapped devices will lag online ones.

clearsig in full

clearsig packages everything above into one CLI and Python library:

# What does this calldata mean? (ERC-7730 translation)
clearsig translate <calldata> --to <address> --chain-id 1

# What digest will my hardware wallet display before signing? (ERC-8213)
clearsig calldata-digest <calldata>

# EIP-712 typed data — domain, message, and final hash
clearsig eip712 message.json

# Safe transaction hashes (offline) — matches safe-hash-rs byte-for-byte
clearsig safe-hash --chain-id 1 --safe-address 0x... --safe-version 1.4.1 ...

# Safe off-chain messages (e.g. OpenSea sign-in)
clearsig safe-msg --chain-id 1 --safe-address 0x... --message-file msg.txt

# Hash an ERC-7730 descriptor for ERC-8176 attestations
clearsig descriptor-hash registry/<project>/<descriptor>.json

# Bootstrap a starter descriptor for a new contract from Sourcify
clearsig generate --chain-id 1 --to 0x... --owner USDC

# Encode and decode calldata against a signature (offline)
clearsig calldata "approve(address,uint256)" 0x05C54380408aB9c31157B7563138F798f7826aA0 1
clearsig calldata-decode "approve(address,uint256)" 0x095ea7b3...

# Function-selector primitives
clearsig sig "approve(address,uint256)"     # → 0x095ea7b3
clearsig keccak "approve(address,uint256)"  # full keccak256
clearsig 4byte 0x095ea7b3                   # reverse-lookup via 4byte.directory

Everything except 4byte runs offline against a local copy of the ERC-7730 registry, so signers can verify on an air-gapped machine. The hashing code is cross-checked byte-for-byte against viem for EIP-712 and safe-hash-rs for Safe hashes, so the digests clearsig produces are the digests the rest of the ecosystem agrees on. clearsig generate uses Sourcify — auto-traversing proxies to the implementation — to bootstrap descriptors from verified ABIs.

The full surface, with worked examples for Safe multisig, Aave, zkSync, and Universal Router edge cases, is in the clearsig README.

What Cyfrin is committing to

Clear signing is one of the most leveraged places to spend security effort in the next few years. The gap between a $1.5 billion exploit and a non-event is often whether the signers could read the bytes in front of them. Cyfrin's position in this fight is deliberate: we don't ship a hardware wallet, and we have no economic interest in any particular one winning. That's exactly what makes us useful as a descriptor auditor — wallets and protocols can attest to our reviews without picking a side. Specifically, Cyfrin is committing to:

  • Auditing ERC-7730 descriptors. Descriptors are a security artifact in their own right — a wrong descriptor can make a malicious transaction look benign. We will be reviewing descriptors submitted to the registry and attesting (via ERC-8176, on EAS) to ones we sign off on. The auditor instructions in the registry formalize what an auditor must verify.
  • Contributing to walletbeat. The objective tracker for how well wallets — software and hardware — protect their users. Clear signing belongs on the report card.
  • Maintaining clearsig, ERC-8213, and the broader clear-signing toolkit. Alongside clearsig, we maintain safe-hash-rs (offline Safe transaction hashing), chain-tools (calldata decoding and other signing utilities), and the Wise Signer Snap for MetaMask — which will be picking up ERC-8213 support shortly. All MIT-licensed; an index lives at docs.cyfrin.io.
  • Continuing the standards work. Clear signing is not done — there are open questions around descriptor lifecycle, attestation discovery, the Wire Protocol for air-gapped devices, and what to do when contracts mutate after a descriptor is published. We will keep iterating with the working group on those.

Acknowledgements

The launch wouldn't be here without years of work from the ecosystem. Specifically:

  • Ledger for originating ERC-7730 and bootstrapping the first registry, early tooling, and educational efforts. The version landing today builds directly on that work.
  • Trezor for sustained investment in transaction parsing and on-device UX, shaping how the industry thinks about the problem.
  • Keystone and GridPlus for being the first hardware wallets (that we've seen) to do ABI decoding directly on the signing device, rather than relying on a companion app. The principle that the device — not its host — should display the decoded transaction is what makes clear signing meaningful in the first place.
  • The full working group — Ledger, Trezor, MetaMask, WalletConnect, Keycard, ZKnox, Blockaid, Fireblocks, Zama, Sourcify, Argot, and the EF's Trillion Dollar Security Initiative — for making this a multi-vendor, multi-team effort rather than a single-vendor push.

What to do with this

  • Protocols: publish a descriptor for your contracts. If you want users to trust what they sign, give them something to read. clearsig generate produces a starting point from a verified ABI; refine intents and labels by hand.
  • Auditors: attest. The trust graph only works if reviewers actually plug in. The auditor flow is documented here.
  • Wallet developers: integrate the libraries shipping today. Make blind signing the exception, not the default.
  • Signers: stop signing things you can't read. Verify with a second device when the stakes are high — clearsig translate and clearsig calldata-digest are designed exactly for this.

Resources

Secure your protocol today

Join some of the biggest protocols and companies in creating a better internet. Our security researchers will help you throughout the whole process.
Stay on the bleeding edge of security
Carefully crafted, short smart contract security tips and news freshly delivered every week.