DEV Community

ohmygod
ohmygod

Posted on

The AppsFlyer SDK Hijack: How a Trusted Marketing Script Became the Largest Crypto Address-Swapping Attack in 2026

On March 9, 2026, security researchers at Profero noticed something terrifying: obfuscated JavaScript was being served from websdk.appsflyer.com — the official domain of one of the world's largest marketing analytics SDKs, used by over 15,000 businesses across 100,000 applications.

The injected code did one thing brilliantly: it watched for cryptocurrency wallet addresses on any page, silently replaced them with attacker-controlled addresses, and exfiltrated the originals. Bitcoin, Ethereum, Solana, Ripple, TRON — all targeted.

This wasn't a smart contract exploit. No flash loans. No oracle manipulation. Just a compromised third-party script running with full page access on thousands of websites, including DeFi frontends, exchanges, and fintech platforms.

The Kill Chain: From Domain Registrar to Wallet Drain

The attack unfolded in three stages:

Stage 1: Domain Registrar Compromise (March 9)

AppsFlyer later confirmed a "domain registrar incident" that allowed attackers to inject unauthorized code into the Web SDK served from their CDN. The mobile SDK was unaffected — this was surgically targeted at browser-side JavaScript.

Stage 2: Stealth Injection

The malicious payload was designed for maximum stealth:

// Pseudocode reconstruction of the attack pattern
// The real code was heavily obfuscated

// 1. Preserve normal SDK functionality
const originalInit = window.AF.init;
window.AF.init = function(...args) {
  originalInit.apply(this, args);
  initAddressMonitor();
};

// 2. Runtime string decoding (anti-static-analysis)
const config = decode(obfuscatedBlob);

// 3. Hook into network requests
const origFetch = window.fetch;
window.fetch = async function(url, opts) {
  if (containsWalletAddress(opts?.body)) {
    opts.body = swapAddress(opts.body);
    exfiltrate(originalAddress, metadata);
  }
  return origFetch.call(this, url, opts);
};
Enter fullscreen mode Exit fullscreen mode

Key stealth techniques:

  • Normal SDK behavior preserved — analytics tracking continued working, so monitoring dashboards showed no anomalies
  • Runtime-only string decoding — attacker wallet addresses never appeared in static analysis of the script
  • Network request hooking — intercepted fetch() and XMLHttpRequest to catch wallet addresses in form submissions and API calls
  • Selective activation — only triggered on pages where crypto-related activity was detected

Stage 3: Address Swap and Exfiltration

When a user entered or displayed a wallet address on any affected page:

  1. The script detected the address format (BTC, ETH, SOL, XRP, or TRX)
  2. Replaced it with a corresponding attacker wallet
  3. Exfiltrated the original address + page URL + timestamp to an external endpoint
  4. The user saw the attacker's address and sent funds to it

The exposure window was approximately 36 hours: March 9, 22:45 UTC through March 11.

Why This Matters More Than Another Smart Contract Hack

This attack highlights a fundamental blind spot in Web3 security:

Your DeFi frontend is only as secure as your weakest third-party script.

Most DeFi teams obsess over smart contract audits (rightfully so), but their frontends load dozens of third-party scripts — analytics, marketing attribution, error tracking, A/B testing, customer support widgets — each running with the same privileges as your own code.

A single compromised SDK can:

  • Read every form field including private keys pasted into import flows
  • Modify displayed wallet addresses before the user copies them
  • Intercept transaction parameters before they reach your signing logic
  • Exfiltrate session tokens to hijack authenticated sessions

The AppsFlyer incident isn't the first. It's just the latest in a pattern:

Date Incident Impact
Dec 2024 Ledger Connect Kit CDN compromise Wallet drainer injected into dApps
Mar 2025 event-stream npm supply chain Bitcoin wallet stealing code in popular package
Nov 2025 Lottie Player CDN hijack Crypto drainer on websites using animation library
Mar 2026 AppsFlyer SDK hijack Address swapping across 100K+ applications

The Defense Playbook: Hardening Your DeFi Frontend

1. Subresource Integrity (SRI) — Your First Line of Defense

SRI lets browsers verify that fetched scripts haven't been modified:

<!-- Instead of this: -->
<script src="https://cdn.example.com/sdk.js"></script>

<!-- Use this: -->
<script
  src="https://cdn.example.com/sdk.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6..."
  crossorigin="anonymous"
></script>
Enter fullscreen mode Exit fullscreen mode

The catch: SRI breaks when vendors update their scripts (which they do frequently). For marketing SDKs that auto-update, you need a proxy approach — self-host a pinned version instead of loading from vendor CDN. Pin to a specific version and update manually after review.

2. Content Security Policy (CSP) — Restrict Script Origins

A strict CSP header limits where scripts can load from and what they can do:

Content-Security-Policy:
  script-src 'self' https://cdn.yourapp.com;
  connect-src 'self' https://api.yourapp.com https://rpc.yourchain.com;
  frame-src 'none';
Enter fullscreen mode Exit fullscreen mode

Critical for DeFi: The connect-src directive prevents injected scripts from exfiltrating data to attacker-controlled servers. Even if a script is compromised, it can't phone home.

3. Script Isolation with Web Workers or Iframes

Run third-party analytics in isolated contexts:

// Sandboxed iframe for analytics (no access to parent page DOM)
const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts';  // No allow-same-origin!
frame.src = '/analytics-sandbox.html';
document.body.appendChild(frame);
Enter fullscreen mode Exit fullscreen mode

Or use Partytown to offload third-party scripts to a web worker, stripping them of DOM access.

4. Client-Side Address Verification

Never trust a displayed address — verify it before signing:

function verifyRecipientAddress(
  displayedAddress: string,
  intendedAddress: string
): boolean {
  if (displayedAddress !== intendedAddress) {
    console.error('ADDRESS MISMATCH DETECTED - possible injection');
    reportSecurityIncident({
      type: 'address_mismatch',
      displayed: displayedAddress,
      intended: intendedAddress,
      timestamp: Date.now()
    });
    return false;
  }
  return true;
}
Enter fullscreen mode Exit fullscreen mode

5. Runtime Script Monitoring

Implement mutation observers to detect unauthorized DOM modifications:

const observer = new MutationObserver((mutations) => {
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      if (node.tagName === 'SCRIPT' && !isAllowedScript(node.src)) {
        node.remove();
        reportUnauthorizedScript(node.src);
      }
    }
  }
});

observer.observe(document.documentElement, {
  childList: true,
  subtree: true
});
Enter fullscreen mode Exit fullscreen mode

6. PCI DSS 4.0.1 Compliance

PCI DSS 4.0.1 Requirements 6.4.3 and 11.6.1 now mandate:

  • Continuous inventory of all scripts on payment pages
  • Integrity monitoring to detect unauthorized modifications
  • Justification for each third-party script's presence

If your DeFi frontend handles fiat on-ramps or processes card payments, these requirements are legally binding. Even if they're not, they represent security best practices every Web3 frontend should follow.

The Uncomfortable Truth

The AppsFlyer attack exposed a systemic problem: DeFi's security model has a massive gap between the contract layer and the user.

We audit Solidity. We fuzz Anchor programs. We formally verify invariants. Then we serve the frontend through a CDN loaded with 47 third-party scripts, any one of which can read, modify, or exfiltrate everything the user sees and types.

The attack worked because:

  1. Trust was transitive — sites trusted AppsFlyer's CDN, which was compromised
  2. No integrity checks — scripts loaded without SRI hashes
  3. Excessive privileges — a marketing SDK had full DOM access including to wallet interaction pages
  4. No monitoring — the swap was invisible until Profero caught it

Until DeFi teams treat their frontend supply chain with the same rigor as their smart contracts, this pattern will repeat. The next attack might not be 36 hours. It might be 36 days before anyone notices.

Action Items

For DeFi developers:

  • Audit every third-party script on your frontend today
  • Implement SRI or self-host pinned versions
  • Deploy a strict CSP with explicit connect-src restrictions
  • Isolate analytics scripts from transaction-critical pages
  • Add client-side address verification before signing

For users:

  • Always verify the full wallet address (not just first/last 4 characters) before confirming a transaction
  • Use hardware wallets that display the recipient address on-device
  • Be suspicious if a previously saved address looks different
  • Check browser developer tools for unexpected network requests

For the industry:

  • Treat frontend security as a first-class audit category
  • Develop standards for third-party script governance in Web3
  • Build browser extensions that detect address swapping in real-time

The AppsFlyer SDK serves over 100,000 applications. For 36 hours, every one of them was a potential crypto-stealing weapon. Smart contract audits won't save you from this.

Top comments (0)