Problem statement

On 21 Feb 2025, Bybit lost ~$1.46B, the largest crypto theft ever, and no smart contract was exploited. Attackers compromised one Safe{Wallet} developer machine and modified one JavaScript file in the S3 bucket that serves Safe's web app. The UI showed a normal transfer, the hardware wallets showed an unreadable hash, and the signers approved a transaction that handed over the cold wallet.

It's a pattern: BadgerDAO (~$120M, injected script), Curve and Balancer (DNS hijacks), Ledger Connect Kit (poisoned npm package injected a drainer into dozens of dApps), Compound and Celer (Squarespace DNS hijacks). Contracts get audited; the frontend users actually sign with is verified by no one. HTTPS protects the connection, not a compromised server. Transaction simulation fails when the UI lies and the hardware wallet blind-signs a hash. That's the unsolved problem.

Solution

FrontSeal gives every frontend release a tamper-proof seal on-chain and makes the wallet check it before any signature prompt.

  1. Seal. CI hashes every file of a build (SHA-256) and proposes the manifest root to the FrontSealRegistry contract (npm run seal).
  2. Co-sign. The release stays Pending until m-of-n publishers approve it. One stolen laptop (Bybit's root cause) can't ship code.
  3. Verify. Before showing a signature prompt, the wallet re-hashes the code running in the tab and calls verify(appId, root). It signs only if the root is Active, and it names the exact file that was tampered with.
  4. Kill switch. Any single publisher can revoke a release. Every FrontSeal wallet stops signing for it in the next block.

Why blockchain: a seal stored on the same server as the code gets swapped along with it. The seal needs a home the attacker can't write to: public, append-only, governed by m-of-n. That's a smart contract, which makes FrontSeal Certificate Transparency for dApp frontends. (Meta's Code Verify does this for WhatsApp Web with Cloudflare as the trusted third party. We replace the trusted third party with a contract.)

Prototype / MVP

A working Attack Lab that replays the Bybit attack against a live FrontSealRegistry contract:

  • Original build + FrontSeal: every file hash matches sealed v1.0.0, so the wallet signs and Cold Storage receives 250 ETH.
  • Attacker-modified app.js, no FrontSeal: the UI still says "Cold Storage", but the signed transaction sends 250 ETH to 0xbadc0de….
  • Same attack, FrontSeal on: app.js doesn't match the seal (a6e8…17f0 ≠ 5cf6…fb0c) and the root was never approved on-chain, so signing is blocked before any signature exists.
  • Registry: a CI-sealed v1.1.0 stays Pending until a second publisher approves. One publisher can revoke instantly, and the full transparency log comes from on-chain events.

Technology stack

  • Chain: EVM (local Hardhat network, chain id 31337), deployable to any EVM chain/L2
  • Smart contract: Solidity 0.8.24, FrontSealRegistry (m-of-n activation, 1-of-n revocation, verify() view). 7 Mocha/Chai tests. About 250k gas to seal a release, about 61k gas to revoke.
  • Tooling: Hardhat 2, ethers v6, Node.js CI sealing script
  • Frontend: React 19 + TypeScript + Vite
  • Crypto: WebCrypto SHA-256 in the wallet, Node crypto in CI (same canonical manifest algorithm)

Challenges we ran into

  • Making the wallet check verify the bytes actually served rather than trusting the manifest. The wallet recomputes the root from the fetched files and checks the claimed manifest separately, so it can tell "tampered file" apart from "unknown release".
  • Designing governance so a single compromised key can't ship code, but a single honest key can stop it (m-of-n to activate, 1-of-n to revoke).

Accomplishments that we're proud of

  • An end-to-end replay of the largest crypto hack in history, blocked by a ~160-line contract.
  • The wallet points at the exact tampered file instead of a generic warning.

What we learned

The biggest losses in Web3 now happen between the user and the contract. Blockchains are an ideal root of trust for the off-chain code that talks to them.

What's next

  • A browser extension and MetaMask Snap that block signature requests from unsealed origins
  • Safe{Wallet} Guard integration, so the chain itself rejects transactions proposed from unsealed UIs
  • Reproducible-build attestations (EAS) linking each root to a Git commit and an audit
  • Public watchtowers that re-hash sealed dApps continuously; deployment on an L2 with ENS frontseal records

Built With

Share this project:

Updates

Submission history