Front-End Compromise Approval Phishing / Injected Wallet-Permission Prompt

  • Name: front-end compromise approval phishing / injected wallet-permission prompt
  • Category: exploit pattern / front-end compromise / approval phishing / ice phishing / wallet-permission abuse
  • Summary: Some crypto incidents do not break the protocol’s contracts at all. Instead, the attacker compromises the project’s front-end delivery path — CDN, DNS, edge worker, tag manager, build pipeline, or another web control point — and changes the wallet prompt shown to users. The victim still visits the correct domain and signs with their own wallet, but the signed action is an attacker-chosen approve, increaseAllowance, permit, Permit2 authorization, or similarly dangerous delegation. Once enough permissions accumulate, the attacker drains wallets directly. The preserved failure is not users clicked the wrong site; it is that the site itself became malicious while retaining the project’s trust. Routing rule: stay here when one protocol’s own domain-delivery stack became the malicious prompt surface; use canonical-domain runtime-byte integrity for the positive-design question of what that real domain should have proved before a user trusted it; use third-party runtime allowance and integrity pinning when the sharper browser-policy question is why that real domain was still allowed to execute mutable remote wallet code at all; pivot to software-supply-chain-compromise when many otherwise honest sites inherited that prompt through a shared package, SDK, or runtime loader; pivot further to release-provenance-failure when the sharpest lesson is that reviewed source, published artifact, runtime selection, and browser-fetched bytes stopped being the same trusted object.

Three signer-prompt authority promotions healthy systems should not collapse

  • Some canonical signer-facing domain and runtime path exists.
  • That live path still counts as the exact protocol-authored spender / permit / signature prompt users meant to trust for this action.
  • That accepted prompt still deserves this much live wallet authority right now.
  • This family appears when teams preserve the first claim better than the second, and the second better than the third.
  • The dangerous flattening is to treat the wallet prompt came from the right site as if it also proved the runtime bytes still preserved the intended spender truth and the authority being requested is still appropriately small for the current mode.
  • Healthy systems separate those promotions on purpose: canonical-domain integrity proves the user is still on the right trust root, runtime-byte integrity proves the live prompt still expresses the intended spender or permit semantics, and approval-scope design plus emergency degradation policy prove how much authority that still-authentic prompt is allowed to request.

Quick classifier

  • Stay here when one protocol’s own registrar / DNS / CDN / edge worker / HTML bootstrap / tag-manager / CI-delivery stack became the malicious wallet-prompt surface.
  • Use the shorthand same real site, different edge-served bytes for BadgerDAO, where the browser stayed on the real Badger domain but Cloudflare-controlled edge behavior rewrote signer-facing JavaScript.
  • Use the shorthand same canonical domain, different registrar-controlled answer for Balancer.fi EuroDNS hijack, where social engineering at the registrar layer changed the nameserver answer for the real domain before Balancer-controlled delivery could even begin.
  • Use the shorthand same canonical domain, different resolver-controlled site for Curve Finance DNS hijack, where the naming layer stopped proving that the browser was even reaching Curve-controlled delivery.
  • Pivot first to software-supply-chain-compromise when the decisive compromise first lived upstream in a shared package, wallet SDK, loader, CDN-backed dependency, or other ecosystem component that many otherwise honest downstream sites inherited; Ledger Connect Kit is the clean same real site, different loader-resolved bytes cousin there.
  • Pivot further to release-provenance-failure when the sharper preserved lesson is which exact reviewed source, built artifact, published package, runtime-selected URL, or browser-fetched byte stream drifted away from the thing operators thought they had authenticated.
  • Pair with third-party runtime allowance and integrity pinning when the sharper browser-policy question is why the real signer-facing page still had permission to execute mutable remote code at all, even if the decisive compromise stayed inside that one protocol’s own delivery stack.
  • What it is:
    • A protocol relies on a web front end to prepare wallet transactions or typed-data signatures.
    • The attacker gains control of some web-delivery layer rather than of the protocol’s onchain contracts.
    • The compromised front end injects an extra spender approval, swaps a legitimate spender for an attacker-controlled one, or harvests an offchain signature that later authorizes token movement.
    • Users sign a real onchain or offchain authorization from the genuine project domain, often during an otherwise normal deposit, claim, or swap flow.
    • The attacker later exercises those approvals or signatures to pull assets from user wallets.
  • Typical preconditions:
    • Users trust the protocol’s canonical web domain and the wallet UX does not make the dangerous field obvious.
    • The protocol commonly requires token approvals, permit signatures, or other delegation flows as part of normal usage.
    • The compromised front end can selectively target high-value wallets or intermittently enable the malicious prompt to avoid detection.
    • Victims hold ERC-20s or vault receipt tokens that can be transferred once spender authority exists.
    • There is no independent transaction-decoding, allowlist, or simulation layer that reliably warns users this spender is not the protocol you think it is.
  • Common vulnerable surfaces:
    • CDN / edge compute layers such as Cloudflare Workers
    • DNS, registrar, or domain-routing control
    • tag-manager, analytics, chat-widget, or third-party script injection paths
    • CI/CD credentials, front-end build pipeline takeover, or one protocol’s own release/distribution path
    • wallet-connection widgets or embedded SDKs that the protocol itself serves or configures on its own domain-delivery path
    • If the malicious prompt instead arrives because many otherwise honest sites inherited one poisoned shared package, wallet SDK, or runtime loader from upstream distribution, route that narrower branch under software-supply-chain-compromise rather than keeping it here as only a generic front-end compromise bullet.
  • Exploit sequence:
    1. The attacker compromises a web-delivery control point for a legitimate protocol interface.
    2. They inject JavaScript or modify front-end transaction-construction logic.
    3. When a victim performs a normal action, the interface presents an attacker-chosen approval or signature request instead of, or in addition to, the intended action.
    4. The victim signs because the domain, app branding, and surrounding workflow still look legitimate.
    5. The attacker silently accumulates approvals or reusable signatures across many wallets.
    6. Once enough value is exposed, the attacker drains wallets with transferFrom() or equivalent permit-based spending flows.
  • Variants:
    • Injected approve() / increaseAllowance() prompt — the front end asks for a spender approval to an attacker EOA or contract while pretending to stage a routine action.
    • Permit phishing — the attacker captures an EIP-2612 or Permit2 signature and later submits it onchain without the victim sending a transaction themselves.
    • Spender-substitution attack — the UI still asks for a legitimate-looking approval, but the spender address is swapped from the real protocol router to the attacker.
    • Selective wallet targeting — the malicious code only fires for high-balance wallets, certain token holders, or some percentage of sessions, which delays discovery.
  • Detection heuristics:
    • Monitor canonical front ends for newly introduced spender addresses, typed-data domains, and approval destinations.
    • Alert when users begin approving EOAs or previously unseen contracts from the protocol interface.
    • Track bursts of approvals to one address from many unrelated users immediately before drains.
    • Treat front-end integrity changes with the same seriousness as deployer-key or proxy-admin events.
    • Ask whether the protocol can independently verify what spender address the UI is currently presenting to users.
  • Defenses:
    • Harden DNS, CDN, edge-worker, CI/CD, and script-supply-chain controls as production-critical custody infrastructure.
    • Prefer exact-amount approvals, short-lived permits, spender scoping, and one-shot flows over durable unlimited allowances.
    • Use wallet and front-end transaction decoding that displays spender identity and flags EOAs or unknown contracts aggressively.
    • Add out-of-band monitoring for unusual approval patterns, especially many users approving the same fresh address.
    • Minimize third-party script surface and require strong review plus integrity controls for any code that can influence wallet prompts.

What sound design looks like

  • The protocol treats signer-surface reachability, signer-prompt truth, and surviving approval budget as separate control questions rather than one vague the request came from our site comfort claim.
  • The protocol treats its canonical signer-facing domain as custody-critical infrastructure, not as a marketing layer sitting outside the security boundary.
  • Wallet-critical pages prove a stable chain of custody from registrar and DNS control through CDN / edge policy, HTML bootstrap bytes, loaded JavaScript, and any runtime-selected wallet SDK or loader.
  • The page that asks for signer authority is deliberately boring: minimal third-party runtime surface, few mutable control points, explicit spender identity, and clear separation between routine product UX code and wallet-prompt construction.
  • Approval flows fail closed toward smaller authority. Exact-amount approvals, per-action permits, short expiries, spender pinning, and staged confirmation are preferred over ambient unlimited allowances.
  • Front-end operators can detect and revoke trust faster than attackers can harvest it: byte-diff monitoring, approval anomaly alerts, emergency pause banners, and rapid spender denylisting all belong in the response model.
  • Users are not expected to reverse-engineer calldata from first principles every time. The protocol and wallet stack collaborate to make who gets to spend what, for how long, and why now visible before signature time.
  • If the canonical domain cannot currently prove runtime integrity strongly enough, the protocol narrows what signer authority that page is allowed to request until it can.

Failure-prevention checklist

  • Inventory every signer-critical control point for the canonical domain: registrar, DNS provider, nameserver delegation, CDN / edge config, CI/CD, static hosting bucket, tag manager, wallet SDK loader, analytics scripts, and emergency cache-purge credentials.
  • Separate site can render from site can ask for wallet authority. The smaller, more static, and more reviewable the signer-facing runtime is, the less one compromised widget or edge rule can do.
  • Pin or strongly constrain spender destinations, typed-data domains, router addresses, and permit targets so a runtime mutation cannot silently substitute an arbitrary EOA or fresh contract.
  • Prefer exact-amount approvals, transaction-bound permits, expiry-bounded signatures, and one-shot authorization patterns over standing unlimited allowances.
  • Add runtime integrity checks for the delivered HTML bootstrap, core JavaScript bundles, and wallet-prompt construction path; alert on unexplained byte drift, surprise third-party script loads, or changed spender-routing config.
  • Minimize or eliminate third-party scripts on wallet-critical routes. If they remain, require explicit review, integrity pinning where possible, and a documented reason they are allowed to influence signer-adjacent UI.
  • Build emergency response paths before the incident: maintenance mode, wallet-warning banners, fast DNS / CDN rollback, spender denylist communication, and user allowance-revocation guidance.
  • Monitor onchain approval patterns from the protocol UI: bursts to EOAs, brand-new spender contracts, sudden Permit2 domain changes, or many unrelated wallets authorizing the same unexpected address.
  • Make release and deploy provenance auditable. Operators should be able to answer which reviewed source produced the live wallet-prompt bytes, who pushed them, and how rollback authenticity would be proven.
  • Drill the frontend became a wallet drainer scenario as a custody incident, not as a generic web outage. The first question is who may already have granted attacker spend rights, not merely when the page will be back.

Audit prompts

  • Which exact systems can change the bytes a wallet user receives at the canonical domain: registrar, DNS, nameservers, CDN rules, edge workers, build pipeline, object storage, feature flags, tag manager, or third-party loaders?
  • Does the live signer-facing page load any remote JavaScript, SDK, config blob, or iframe that can change spender selection or typed-data contents after the main bundle was reviewed?
  • If an attacker controlled one delivery layer for one hour, what largest authority could they ask users to sign: unlimited ERC-20 approval, Permit2 blanket permission, EIP-2612 permit, NFT approval-for-all, account-abstraction session key, or something even broader?
  • Are spender addresses, permit targets, and typed-data domains hard-pinned in reviewed code, or are they mutable through CMS fields, API responses, environment variables, edge config, or third-party runtime state?
  • What independent signal would detect that many users are suddenly approving the same fresh address from the protocol interface before drains begin?
  • Can the protocol warn users in-product or out-of-band fast enough to stop additional signatures once front-end compromise is suspected?
  • How quickly can operators revoke or neutralize the damaged path: rollback bytes, disable wallet actions, rotate credentials, freeze edge rules, or publish spender-block lists to wallet partners?
  • Do wallet simulations and decoding layers show enough context for a user to distinguish approve the protocol router from approve attacker EOA 0x... without expert calldata reading?
  • Are incident drills and access controls stricter on signer-facing routes than on read-only content routes, or does the organization still treat them as one generic web property?
  • If the protocol depends on a shared wallet SDK, remote config service, or CDN-hosted package, should this note still be the primary classifier, or does the sharper preserved lesson really belong under software-supply-chain-compromise or release-provenance-failure?

Lessons that should already be standard

  • The user reached the real domain, the live runtime still preserved the intended spender / permit truth, and the prompt still deserved this much wallet authority are three different claims.

  • The canonical domain is a custody surface once it can ask for wallet authority. Contracts are safe does not matter if the site can still manufacture approvals.

  • Front-end compromise is not only a web-security problem. In crypto it is often delegated-spend capture at scale.

  • Unlimited allowances turn brief delivery compromise into durable theft rights. Smaller, shorter-lived approvals are not UX niceties; they are blast-radius controls.

  • Runtime integrity matters at the byte level, not just at the source-repo level. A reviewed React app is irrelevant if edge-served JavaScript, DNS answers, or shared loaders can diverge underneath it.

  • Wallet UX is part of the control surface. If spender identity is hard to read, attacker-controlled prompts inherit the protocol’s brand trust too easily.

  • Third-party script convenience is governance over signer trust. If an analytics tag, chat widget, or wallet loader can influence prompts, it belongs in the threat model as a potential custody dependency.

  • Response speed matters twice: first to stop new malicious signatures, then to help users revoke already-granted authority before drains finish.

  • Same real site is not sufficient authentication. Users and operators both need evidence that the runtime bytes behind that site are still the ones allowed to request wallet permissions.

  • High-signal incidents:

    • BadgerDAO Cloudflare Worker injected approval drain (2021-12-02) — a compromised Cloudflare API key let the attacker intermittently inject malicious JavaScript into the genuine Badger front end, collect hundreds of wallet approvals to an attacker EOA, and then drain about 2,076.54 BTC-equivalent from users without touching Badger’s audited contracts.
    • approval drain (2023-09-20) — a social-engineered registrar-side nameserver change let the real balancer.fi hostname serve a phishing frontend that mixed approvals, permits, and Permit2-style authorities, showing that registrar support and TLD control paths are already signer-authority infrastructure.
    • malicious approval drain (2022-08-09) — a DNS / nameserver hijack redirected the real curve.fi domain to an attacker-controlled interface that asked users to approve malicious spender 0x9eb5f8e83359bb5013f3d8eee60bdce5654e8881, proving that domain-resolution control alone can become wallet-drain authority.
    • Ledger Connect Kit npm supply-chain wallet drainer (2023-12-14) — a phished former employee’s still-authorized NPMJS publishing access let the attacker poison a shared wallet-connect dependency, so many legitimate dApps simultaneously served drainer prompts from their real domains without their own contracts being compromised. The more specific preserved branch now lives at software-supply-chain-compromise.

Internal linkages

Control surface