On December 2, 2021, BadgerDAO — Ethereum's largest Bitcoin yield aggregator — discovered that $120 million had vanished from roughly 100 user wallets. The contracts were untouched, the vaults had been audited, and no private key was stolen. What broke was the website. For 22 days, a malicious script injected through a compromised Cloudflare API key had been silently rewriting every transaction users approved on app.badger.com, swapping the intended Badger DAO hack victim's vault deposit for an infinite token approval to an attacker-controlled address. When the approvals were later drained with transferFrom, the blockchain did exactly what it was told — because the lie happened in the browser, not on-chain. Understanding why this frontend exploit DeFi incident succeeded — and why Content-Security-Policy, Subresource Integrity, and least-privilege API tokens would have stopped it — reframes DeFi security for every team that still treats its website as marketing rather than as a trust boundary.
What BadgerDAO Does and Why Its Bitcoin Vaults Made a Juicy Target
BadgerDAO launched in late 2020 with a single thesis: Bitcoin holders want yield without leaving their BTC exposure. The protocol built Setts — yield-bearing vaults on Ethereum that accept Bitcoin-pegged assets (wBTC, renBTC, ibBTC) and Curve LP tokens, then auto-compound Curve, Convex, and Badger rewards. By November 2021, Badger managed roughly $1.5 billion in total value locked, with the flagship bveCVX and ibBTC / renBTC Curve vaults holding deep BTC liquidity that few other aggregators matched.
Two properties made Badger a uniquely valuable frontend target. First, its users were BTC whales — wallets holding 50–1,000+ wBTC (each worth ~$55k at the time), not retail dust. A single compromised approval could be worth $50 million. Second, Badger's vault tokens (bveCVX, bCRV, bBadger, ibBTC LP) are ERC-20s that behave like money — once an attacker holds an infinite approval, transferFrom works at any future block without further user interaction. There is no timelock on an allowance, no vault-level circuit breaker, and no issuer freeze (unlike USDT, wBTC is not centrally freezable in the same way). The frontend was the narrowest point that controlled the widest value.
Crucially, Badger's vault contracts themselves had been audited (Haechi, 2021) and contained no reentrancy or accounting flaw. The exploit needed no contract bug because it never touched contract logic — it obtained legitimate approvals through a compromised user interface, then used the contracts exactly as designed. That distinction is why post-mortem checklists for lending and vault protocols now separate "contract audit" from "frontend trust boundary review" as two independent gates.
Timeline: 22 Days Inside the Website Before Anyone Noticed
The Badger DAO hack was an APT-style intrusion — persistence mattered more than speed.
November 10, 2021 — The attacker, having obtained a Cloudflare API key belonging to a BadgerDAO engineer, used Cloudflare's API to create or modify a Cloudflare Worker route on api.badger.com. The Worker injected roughly 40 lines of obfuscated JavaScript into every response served by app.badger.com. Badger later confirmed the key had broad scope (Workers + Zone edit), no IP allowlist, no rotation schedule, and no MFA gate on API use. The injection was live from this date, but drains were staged to avoid early detection.
November 10 – December 1, 2021 (dwell window) — The injected script ran inside every visitor's browser. It wrapped window.ethereum.request, intercepted eth_sendTransaction and eth_sign, and — when the user submitted a legitimate sett deposit — quietly replaced or appended an approve(attackerContract, 0xfff…fff) (MAX_UINT / infinite approval) for whatever tokens the wallet held, after first calling eth_call to check balances and target large holders. The UI still showed the expected transaction details; the approval's spender address (attacker-controlled) was never rendered as a human-readable warning. Over three weeks, more than 100 wallets accumulated infinite allowances to attacker contracts. The attacker rotated the spender address once mid-window to compartmentalize risk.
December 2, 2021, ~00:00–06:00 UTC — Community members on Discord reported unauthorized transferFrom drains. On-chain, the attacker began sweeping the accumulated approvals in batches — not all at once, to keep gas spikes and TVL charts smooth. The largest single victim lost roughly $50 million (wBTC + vault tokens).
December 2, 2021, ~09:00 UTC — BadgerDAO detected the active exploit, paused all vaults and smart contracts via the pause() admin function, and took app.badger.com offline. Cloudflare API keys were revoked, Workers removed, and the malicious script's hash published for verification. No further funds were drained after the pause.
December 2–3, 2021 — PeckShield, BlockSec, and SlowMist published independent root-cause threads within hours, all converging on the Cloudflare API key → Worker injection → infinite approval chain. The badger dao hack analysis hardened from hypothesis to consensus before the official post-mortem.
December 10, 2021 — BadgerDAO published the technical post-mortem on Medium: Cloudflare API key compromise confirmed, injection details, attacker addresses, and a remediation plan (CSP, SRI, token scoping, frontend canary). A treasury-funded reimbursement framework was proposed in subsequent governance posts.
2022–2023 — Forensic tracking (SlowMist, Chainalysis) followed consolidated funds to Tornado Cash deposits in ~100 ETH batches. Of the $120M, roughly $70M+ was obfuscated through the mixer by January 2022; the BTC-heavy composition complicated laundering because wBTC had to be unwrapped and bridged before mixing. No attacker identity was publicly confirmed; no funds were returned.
The Numbers: Where $120 Million Went and Why It Concentrated in BTC
Headlines round to $120 million, but cross-checking aggregators shows expected variance by price snapshot. PeckShield cites $120.3M, BadgerDAO says $120M, and Rekt reports $120M — differences map to BTC's intraday price ($53k–$57k on Dec 2, 2021). Use $120M with the variance noted; precision beyond that is snapshot-dependent.
| Item | Value |
|---|---|
| Headline loss | ~$120M (~$120–121M by USD snapshot) |
| BTC-denominated loot | ~2,100 BTC (wBTC + ibBTC_interest-bearing) ≈ $85–90M |
| BADGER + vault LP | ~151 BADGER + bBadger / bveCVX / bCRV / ibBTC Curve LP ≈ $25–30M |
| Remaining ERC-20s | DIGG, renBTC LP, assorted vault receipts ≈ $5M |
| Affected wallets | ~100 with infinite approvals; ~10 with >$1M loss |
| Largest single victim | ~$50M (single whale's wBTC + sett tokens) |
| Flash loan involved? | No — this was not a flash loan attack; approvals were collected over weeks |
| Funds returned | $0 (0% recovery) — attacker-controlled, no issuer freeze |
| Who bears loss | Users initially; Badger treasury/governance reimbursement framework proposed |
Three details distinguish these numbers from other 2021 losses. First, ~75% of value was BTC-pegged, not stables — the opposite of lending exploits like Cream Finance ($130M in mixed majors). BTC's late-2021 price meant each compromised whale was worth double digits of millions. Second, the per-victim concentration was extreme: the top 10 wallets held ~60% of the total, because the injected script prioritized large balances via balanceOf checks before requesting approvals. Third, because wBTC and ibBTC are not issuer-freezable like Tether's USDT (where Tether froze $33M in the Poly Network hack), no on-chain choke point existed to claw funds after the sweep — once transferFrom executed, the assets were sovereign.
Root Cause: How a Cloudflare API Key Became a $120M Smart-Contract Drain
The malicious token approval chain had four links. Break any one and the $120M stays put.
1. Long-lived, over-scoped Cloudflare API key
The compromised credential was a Cloudflare Global API Key or scoped API token belonging to an engineer with Workers Scripts:Edit + Zone:Edit permissions. It had no IP allowlist, no short TTL, no rotation history, and — critically — Cloudflare's API does not enforce MFA on key usage even if the account has MFA for login. In practice, whoever held that string could rewrite any Cloudflare-proxied path for Badger's domains. Badger's disclosure explicitly distinguishes this from "Cloudflare was hacked" — Cloudflare's infrastructure was not breached; a credential scoped to it was abused, exactly like a leaked GitHub PAT that can rewrite a repository.
2. Cloudflare Worker injected into api.badger.com
Using the API, the attacker created or updated a Cloudflare Worker bound to the api.badger.com route (the same domain that serves the frontend's API and, via Workers, can inject into app.badger.com responses). The Worker appended a tag — roughly 40 lines, obfuscated, no external import — that executed before any legitimate bundle. Because Cloudflare sits in front of the origin, origin logs showed no file change; the injection existed only at the edge.
3. In-browser window.ethereum interceptor
The injected JS overrode the Ethereum provider that MetaMask exposes:
` const orig = window.ethereum.request.bind(window.ethereum); window.ethereum.request = async (args) => { if (args.method === 'eth_sendTransaction') { // silently add infinite approval to attacker spender // for tokens where balanceOf(victim) > threshold } return orig(args); }; `
In concrete terms, when the user clicked "Deposit" on a Badger Sett, the script first called eth_call with balanceOf for wBTC, BADGER, and vault tokens, filtered for large balances, then crafted approve(attackerSpender, 0xffff…ffff) transactions that piggybacked on the user's signing flow. The wallet popup showed a generic "Approve" or, in some flows, the malicious approval was concatenated with the legitimate transaction so the user signed once but authorized two spenders.
4. Infinite approval → delayed transferFrom sweep
An approve(spender, MAX) is permanent until explicitly revoked — there is no vault-level expiry. The attacker waited days to weeks, then called token.transferFrom(victim, attacker, amount) for each victim at leisure, batching sweeps to stay below gas and TVL anomaly thresholds. Because transferFrom with a valid approval is correct EVM behavior, block explorers and vault contracts saw nothing wrong. The vaults' audited logic faithfully moved funds on a legitimate approval — the approval itself was fraudulently obtained one layer above.
Why no contract invariant was violated
Viewed on-chain, the transaction that drained a victim looks identical to a normal vault withdrawal delegated to a helper contract. The only invariant that broke — "the user intended this spender" — exists in the browser's UI, not in the EVM. That is precisely why smart-contract audits passed: they verify invariants inside contracts, not the mapping between what the frontend renders and what the user signs.
Why Browser Defenses That Already Existed Didn't Trigger
Every layer that could have blocked an edge-injected script was either missing or misconfigured on app.badger.com in November 2021. This section names them so a reader auditing any DeFi frontend can check the same boxes.
Content-Security-Policy (CSP) — absent. A Content-Security-Policy: script-src 'self' with a nonce or hash for each legitimate inline script would have caused the browser to refuse execution of the Worker-injected because its origin/hash was not allowlisted. The browser would have logged a CSP violation to the reporting endpoint, which — if anyone was watching — would have surfaced the injection on day one. No CSP was deployed on Badger's frontend at the time (confirmed by post-mortem and CertiK/BlockSec recommendations). The more precise fix is script-src 'self' 'nonce- with a strict reporting URI; 'unsafe-inline' defeats the defense entirely and was, by omission, effectively the policy.
Subresource Integrity (SRI) — not enforced. Even without CSP, marking the frontend bundle with integrity="sha384- causes the browser to hash the fetched script and refuse to execute it on mismatch. An edge-injected script that alters the bundle's bytes would fail SRI. The injected script avoided altering the bundle hash by being appended outside the hashed bundle as a separate , which is exactly why CSP's script-src allowlisting — not just bundle SRI — is the necessary complement.
Cloudflare token hygiene — none of the hardenings. The compromised API key was (a) long-lived with no rotation, (b) scoped broadly beyond Workers, (c) not bound to an IP allowlist, and (d) not monitored by an API audit-log alert. Any one mitigation — scoped token per role, 30-day TTL with rotation, IP binding, or a Slack/PagerDuty alert on Worker script update — would have either prevented the write or cut dwell from 22 days to hours.
Frontend canary / script-hash monitoring — absent. A deployment pipeline that hashes every shipped script and compares the app.badger.com response hash to the expected hash (via an external canary outside Cloudflare) would have caught the extra 40 lines immediately. Modern frontends (e.g., after the Bybit Safe UI exploit in 2025) treat this as a deployment invariant; in 2021 it was rare.
Approval UX — conditioned to trust MAX. DeFi UX since 2020 normalized infinite approvals to save gas on repeated deposits. Users had no reason to question an "Approve" popup that, by habit, they dismissed as protocol overhead. Revocation tooling (Revoke.cash, Etherscan Token Approvals) existed but was not surfaced in any wallet as a default post-transaction hygiene step.
Together, these five missing controls map directly to the five-layer defense checklist in the final section.
The Attacker and How the Exploit Stayed Quiet for Three Weeks
Attribution for the Badger DAO hack remains unresolved publicly; no identity has been confirmed and no funds were returned. What on-chain behavior reveals is an operator who treated the frontend like an APT persistence — not a smash-and-grab.
The injected script was selective: it called balanceOf for each token before requesting an approval, filtered for wallets holding above a threshold (reported as >$100k equivalent), and skipped small balances to limit approval spam that might alert users who inspect eth_sendTransaction logs. The attacker rotated the spender contract once mid-window — a new address replaced the first — suggesting awareness that Etherscan's approval tracker could surface a single spender with 100+ infinite approvals. The sweep phase was batched across hours, not one block, which kept gas fees moderate and TVL charts smooth; Badger's TVL is large enough that a $5–10M decrement looks like normal vault withdrawal volatility.
Unlike flash-loan attacks that must succeed atomically (fail = revert = no loss), this attack had the opposite property: each victim was independent. One user's approval could be harvested and drained without affecting the next. That meant the attacker never needed to risk a revert that would surface the whole scheme, and never needed capital beyond gas. The cost of the attack was ~tens of dollars in gas for the sweeps; the entry cost was a phished or brute-forced API key.
Laundering: Why the Bitcoin Heavy Mix Was Awkward to Hide
Once swept, funds were consolidated into attacker-controlled EOAs — the primary EOA identified in the post-mortem as 0x1fcdb04d0c5364fbd92c73ca8af9baa72c269107 and its associated spender contract. Forensic analysis by SlowMist and Chainalysis describes the next hops:
- BTC-pegged loot was unwrapped/swapped. wBTC and ibBTC Curve LP had to be withdrawn from Badger/Curve, unwrapped, and swapped to ETH via Curve 3Pool and Uniswap to become mixable. Each hop (vault withdrawal → unwrap → swap) produced traceable events and slippage, and delayed consolidation compared to an ETH-native theft.
- ETH was funneled to Tornado Cash in the classic late-2021 pattern: batches of ~100 ETH per deposit, repeated many times. Chainalysis tracked roughly $70M+ moving through Tornado Cash by January 2022; the remainder's path was less clearly clustered because BTC bridging added hops that were not uniformly via Tornado's ETH pools.
- Tornado Cash was not yet sanctioned (OFAC designation came August 2022), so deposits faced no protocol-level freeze — unlike 2023+ cases where mixer pools shrank under compliance pressure.
- Cross-chain bridging was not the primary rail — unlike bridge hacks that immediately hop chains, Badger's attacker stayed on Ethereum because the loot was already Ethereum-settled via wBTC; bridging would have added a second traceable surface.
The unwrapping tax is the reason later frontend/approval attacks shifted to targeting ETH-native approvals (staked ETH, stable LP) where possible: fewer hops between theft and anonymity.
Fund Flow: From a Fake Approval to Real BTC
Condensed end-to-end:
- Entry — Compromised Cloudflare API key (cost: phishing or credential stuffing) → Worker injection on
api.badger.com, Nov 10. - Collection — Every large-balance visitor to
app.badger.comsigns an infiniteapprove(attacker, MAX)without knowing it — ~100 wallets over 22 days. - Sweep — Attacker calls
transferFrom(victim, attacker, balance)per token, per victim — ~$120M leaves victims' wallets for attacker EOAs in batches starting Dec 2. - Consolidation — Vault LP tokens redeemed, wBTC/ibBTC unwrapped, swapped toward ETH via Curve/Uniswap.
- Obfuscation — ETH deposited to Tornado Cash in ~100 ETH batches (~$70M+ by Jan 2022; remainder via assorted swaps/mixers).
- Aftermath — Badger pauses vaults Dec 2, removes Worker, revokes keys; zero funds returned through on-chain negotiation (contrast Poly Network's $611M full return).
What did not happen is diagnostic: no failed DEX routes (unlike Poly's three Curve reverts under frontrunning), no issuer freeze (unlike Poly's $33M USDT freeze by Tether), no chain halt, and no flash-loan fingerprint (unlike Cream/Beanstalk/Euler). The Badger path was invisible precisely because it used the system's correct paths with fraudulently obtained permissions.
Response: Pause, Post-Mortem, and Who Paid
BadgerDAO's response unfolded on the standard DeFi incident clock but with a notable compensation posture.
Containment (Dec 2, 2021). The team invoked the vault pause() admin function, halting deposits, withdrawals, and compounding across all Setts. The frontend was taken offline, Cloudflare Workers and API keys were revoked, and the malicious script hash was published so users could verify its removal. This prevented further transferFrom drains — but by then the approvals that mattered had already been escrowed as allowances, so pause only blocked secondary actions like attacker compounding.
Disclosure (Dec 10, 2021). The official post-mortem disclosed the Cloudflare API key vector, the Worker injection mechanism, the full drain timeline, and the proposed hardening: CSP + SRI on the frontend, scoped/short-lived Cloudflare tokens with IP binding and audit-log alerts, frontend canary hashing, and a migration away from infinite approvals as a default UX. The post-mortem also explicitly stated that Cloudflare's infrastructure was not breached — a credential was compromised — to avoid misattributing the failure.
Recovery discussion (Dec 2021 – 2022). Unlike Poly Network (attacker negotiated a full return) or Euler Finance ($197M largely returned), Badger's attacker did not negotiate and the loot was not issuer-freezable. Badger governance discussed reimbursement funded by treasury reserves, protocol fees, and a new token issuance framework; the final plan used a combination of treasury BADGER and fee revenue over time. The user-facing lesson — that pause() alone cannot claw transferFrom once allowances are granted — is why wallet-level controls (revoke flows, allowance dashboards) are now treated as part of protocol responsibility, not just wallet UX.
Frontend rebuild (2022). The incident catalyzed a broader frontend security reset: Badger rebuilt the frontend pipeline with CI-hashed deployments, CSP reporting, and an explicit decision to treat the website's deployment keys as equivalent to contract deployer keys in operational security.
Lessons: 5 Defenses That Would Have Stopped the Badger DAO Hack
The frontend exploit DeFi pattern is not novel — 2022 saw the Curve frontend hijack ($570k via DNS), and 2025 added the Bybit Safe wallet UI compromise ($1.4B) — but Badger is the reference case where all five standard defenses were simultaneously absent. Any one would have reduced or eliminated the $120M outcome.
1. Scope Cloudflare (and every edge) API tokens to least privilege, with binding and rotation. No single API key should have Workers+Zone edit, global scope, infinite TTL, and world-routable use. Replace every long-lived key with scoped tokens (Workers:Edit only for the specific zone), bind each to an IP allowlist / mTLS, set 30-day expiry with rotation, and alert on every Worker script update via audit-log webhooks to PagerDuty. Treat a Worker-write token as a deployer private key — because it is.
2. Deploy CSP + SRI on every DeFi frontend — and monitor the reporting endpoint. Content-Security-Policy: script-src 'self' 'nonce- (never 'unsafe-inline') plus integrity="sha384- on every bundle causes the browser to refuse an edge-injected script regardless of how it arrived. Ship a reporting URI and alert on the first CSP violation — that violation is the intrusion signal, on day one, not day 22. Local caching of the last-known-good script hash (outside the CDN) provides a second canary.
3. End the infinite-approval default — enforce per-transaction limits and surface revocation. Users were habituated to MAX approvals for gas savings. Protocols should request exact or tightly capped allowances (e.g., amount + 5% for slippage, or per-deposit cap) and wallets should prompt on allowance delta ("this approval gives spender control of your entire wBTC balance — approve instead?"). Integrate Revoke.cash / Etherscan Token Approvals as a post-transaction hygiene step, and add a protocol-level dashboard that flags addresses with >10 outstanding infinite approvals to the same spender — the Badger attacker pattern would have surfaced within hours.
4. Run a frontend integrity canary outside the CDN. A cron job outside Cloudflare (e.g., a pinned canary in a separate cloud provider) that fetches app.badger.com every minute, hashes the response, and compares it to the CI-published hash would have flagged the extra 40 lines on the first fetch after Nov 10. Cloudflare's own logs did show a Worker update, but no one was watching; an external canary removes the "fox guarding the henhouse" failure mode.
5. Add a vault-level transferFrom circuit breaker. Even with approvals, a vault can enforce a per-block / per-hour transferFrom rate limit (e.g., pause if >$2M of transferFrom volume targets a single spender in one block, or >$10M in one hour). This does not replace approvals — it limits blast radius when the approval layer is compromised. Lending protocols adopted borrow caps after Aave v3; vault/aggregator protocols should adopt transferFrom caps for symmetrically large batch-drain risks. Combined with a pause() that also freezes transferFrom on flagged spenders, this would have capped the sweep to a fraction of $120M.
These five compose a trust-boundary model: (1) removes the edge write surface, (2) makes a successful write inert in the browser, (3) removes the infinite-ammo the browser write weaponizes, (4) detects a write even when (2) is bypassed, and (5) contains the damage when (1)–(4) all fail. Badger had none; every protocol shipping a frontend that holds >$10M of approvals should have all five.
Frequently Asked Questions
How much was stolen in the Badger DAO hack? Approximately $120 million (aggregators cite $120–121M depending on the ETH/BTC price snapshot on December 2, 2021). The largest component was ~2,100 BTC in wBTC/ibBTC plus 151 BADGER and Curve vault LP tokens (bveCVX, bCRV). About 100 wallets were affected, with the single largest loss around $50M. The protocol's own post-mortem, PeckShield, BlockSec, and SlowMist all converge on the badger dao 120 million figure within 1% variance — the spread is USD conversion timing, not new on-chain evidence.
How did the Badger DAO hack work? It was a frontend exploit DeFi attack, not a smart-contract bug. An attacker compromised a Cloudflare API key, used it to inject ~40 lines of JavaScript into app.badger.com via a Cloudflare Worker, and had that script intercept window.ethereum.request so that every large-balance user's legitimate vault transaction also signed an infinite approve(attacker, MAX) for wBTC, BADGER, and vault tokens. Days to weeks later, the attacker called transferFrom(victim, attacker, amount) to drain each infinite allowance in batches. The vault contracts behaved correctly — the approval they honored had been fraudulently obtained in the browser. See the root-cause diagram above for the full chain.
How is a frontend exploit different from a smart-contract hack? A smart-contract hack (e.g., Cream's pricePerShare manipulation, Euler' s donation bug) exploits logic inside the contract so that the transaction the user signs is honored differently than intended by the chain. A frontend exploit like Badger's changes what the user signs — the chain honors it exactly as signed, but the UI lied about the spender. That is why contract audits did not catch Badger: the bug was a compromised website, not a compromised invariant. The defense therefore sits in the browser and the CDN (CSP, SRI, token hygiene), not just in Solidity.
Were the stolen funds frozen or returned? Neither — 0% recovery. Unlike the Poly Network hack where Tether froze $33M of USDT, Badger's loot was predominantly wBTC/ibBTC and vault LP tokens, which are not centrally freezable, and the ETH that was swapped out went to Tornado Cash (pre-sanctions in 2021) in ~100 ETH batches — Chainalysis tracked ~$70M+ through the mixer by January 2022. The attacker did not negotiate a return (contrast Poly's white-hat return of the full $611M). Badger governance funded reimbursement from treasury BADGER and protocol fees over 2022.
Can I revoke a malicious token approval after a frontend compromise? Yes — and it is the single highest-leverage user action. An approve(spender, MAX) grants transferFrom rights until you explicitly revoke it. Use Revoke.cash, Etherscan's Token Approvals checker, or call approve(spender, 0) directly, then rotate to a fresh wallet for new activity. Revocation is a gas-costly but immediate kill switch: once the allowance is zero, the attacker cannot sweep that token again even if they still hold the spender contract. As a habit, approve only the exact amount you intend to deposit and keep your allowance surface visible in your wallet's approval dashboard.
What changed in DeFi security after the Badger DAO hack? Three practices became standard for any frontend that can request token approvals. First, Cloudflare token hygiene — scoped, short-lived, IP-bound tokens with audit-log alerting — is now an operational checklist item, not an afterthought. Second, CSP + SRI + external canary is the expected browser defense triad; auditors (BlockSec, CertiK, Trail of Bits) now include frontend trust-boundary reviews alongside contract audits. Third, approval UX reform — per-transaction caps, allowance-delta prompts, and post-transaction revoke nudges — is embedded in wallets and protocols that list BTC or yield-bearing vault tokens as collateral. Later frontend incidents (Curve DNS hijack $570k, Bybit Safe UI $1.4B) reinforced Badger's lesson: the website is part of the attack surface, and it must be defended like a vault.
Conclusion
The Badger DAO hack compresses DeFi's hardest lesson into a single number: $120M, taken without breaking any contract, by breaking the page that asked users to sign. The vaults were audited, the chain was honest, the math was correct — and none of it mattered because a Cloudflare API key with broad scope and no binding could quietly rewrite app.badger.com for 22 days. Each victim signed what looked like a deposit and actually signed away infinite control of their Bitcoin-pegged assets; the attacker then treated those allowances as a bank.
That framing reframes what counts as security. A DeFi protocol is not a set of smart contracts with a website on top — it is a signing ceremony that happens in a browser, mediated by a CDN, rendered by JavaScript, and whispered to a wallet that most users trust on sight. Compromise any one of those links and the contracts will do exactly what they are told with money they should never have touched. The fixes — scoped tokens, CSP/SRI, canary hashing, approval minimalism, and vault-level rate limits — are older than DeFi itself. They were simply not deployed on the one page where they mattered most. In DeFi, every new approval is a new key, and every frontend is a vault door with its own lock.
