Commissioned, Curated and Published by Russ. Researched and written with AI.
What’s New
AppsFlyer has expanded the confirmed exposure window to March 9 20:40 UTC through March 10 10:30 UTC – approximately 14 hours. No public root cause analysis has been released yet. The company confirmed a “domain registrar incident” as the attack vector. Investigation ongoing with external forensic partners.
Changelog
| Date | Summary |
|---|---|
| 15 Mar 2026 | Initial publication. |
On March 9, 2026, something changed about the JavaScript that 15,000 businesses were loading from AppsFlyer’s CDN. For roughly 14 hours, any website serving that script was redirecting cryptocurrency payments to someone else’s wallet – without the user knowing, without the site operator knowing, without any visible error.
The attack is over. The attack surface it revealed is not.
What AppsFlyer Is and Why It’s Everywhere
AppsFlyer is a mobile measurement partner (MMP) – the industry term for platforms that track which marketing campaigns led to which app installs, in-app purchases, and conversion events. It’s the infrastructure behind the “did this ad work?” question that every mobile product team asks. According to the company, its SDK is used by 15,000 businesses across more than 100,000 mobile and web applications.
That scale explains why it ended up in this story. AppsFlyer isn’t embedded on informational pages. It’s embedded on e-commerce checkout flows, fintech apps, and consumer platforms that handle transactions and payment events – because those are the conversion events attribution tools are built to measure. The SDK sits next to payment forms. It’s right next to exactly what the attackers were targeting.
This is worth holding in mind throughout: the attack didn’t randomly land on a high-value surface. Attribution SDKs, by design, live on high-value pages.
What Happened
On March 9, researchers at Profero identified a malicious payload being served from websdk.appsflyer.com – AppsFlyer’s official SDK domain. Reddit’s r/cybersecurity surfaced the issue the same day, before any vendor acknowledgment. The Reddit post noted that DNS for the domain had been updated, switching from AWS infrastructure to GCore CDN at the start of the malicious activity.
AppsFlyer later confirmed to BleepingComputer that the root cause was a “domain registrar incident” – attackers gained control at the registrar layer, redirected DNS, and used that control to serve modified JavaScript from the SDK’s own domain.
AppsFlyer’s status page, updated March 10, described the situation as a “domain availability issue.” That is a significant understatement. The company notified customers of the SDK compromise on March 10, and the exposure window was subsequently confirmed as March 9 20:40 UTC to March 10 10:30 UTC.
The mobile SDK was not affected. Only the web SDK.
The Payload
Independent researcher Daniel Smith deobfuscated two separately captured samples of the payload and published a detailed analysis. The initial characterisation of this as a simple crypto clipper is wrong. This was a professional-grade, modular interception framework with seven distinct components:
- NetHooksmith replaced the browser’s native
fetchfunction and patchedXMLHttpRequestprototype methods, giving the attacker full control over every HTTP request and response flowing through the page – including API calls carrying auth tokens and session data. - ActuateElements monitored the DOM for input activity, with explicit Shadow DOM penetration via monkey-patching
Element.prototype.attachShadow. Many secure payment components use Shadow DOM specifically to isolate inputs from third-party JavaScript. This payload defeated that isolation by intercepting the Shadow Root creation call itself. - Destinations managed a rotating pool of attacker-controlled cryptocurrency wallet addresses, randomising selection to distribute stolen funds across multiple wallets and complicate blockchain analysis.
- Accounting evaluated wallet balances against a configurable minimum threshold before substituting addresses – ignoring low-value wallets to avoid triggering fraud alerts, focusing exclusively on transactions worth stealing.
- KillElements removed DOM elements matching attacker-specified selectors, likely targeting CSP violation banners or competing detection scripts.
- ConsoleGuard replaced every
consolemethod with a no-op. If you had developer tools open during the incident window, you would have seen nothing from the payload’s operation. - XorCipherBytes encrypted C2 communications with a configurable XOR key, using an inline SHA-256 implementation to avoid browser crypto APIs that security tooling might monitor.
The payload was also polymorphically obfuscated – two independently captured samples were functionally identical but structurally distinct, with different variable names, shuffled encoding alphabets, and different file hashes. Signature-based detection catches one build. A fresh build evades immediately.
Targets included Bitcoin, Ethereum, Solana, Ripple, and TRON addresses.
The Registrar Attack Vector
Supply chain security thinking has largely focused on package registries: npm, PyPI, crates.io, RubyGems. The defences built in response – package signing, provenance attestation, lock files, hash verification – all address the question of what code ends up in the artifact. That’s the right question for that attack surface.
A JS SDK served from a vendor CDN domain has a different attack surface entirely.
If an attacker gains control of the domain or DNS records, they can serve any content they want from a URL that every integrator has already whitelisted. The attack doesn’t require compromising the vendor’s code repository. It doesn’t require access to their CI/CD pipeline, their build signing keys, or their package registry credentials. It bypasses all of that. The attacker goes underneath the code supply chain and attacks the delivery infrastructure directly.
In the AppsFlyer case, the attack appears to have operated at the domain registrar layer – the account that controls where websdk.appsflyer.com resolves. Compromise that account, update the DNS record, point the domain at your own infrastructure, and every site that loads the SDK immediately starts serving your code. No pull requests. No build artifacts. No package versions to audit.
This is different from the npm supply chain attacks covered in PhantomRaven or the Rust crates CI/CD attack. Those attacks required getting malicious code into the artifact pipeline. This one treated the domain itself as the delivery mechanism. The broader cascade piece connects this to a pattern of third-party trust being weaponised at scale – but the registrar vector specifically is underexplored.
Hardening against this is not the same as hardening your package dependency chain. Registrar account security, DNS monitoring for unexpected record changes, and CDN provider diversity are different controls from the ones most security programmes focus on.
Crypto Wallet Substitution Is a Manipulation Attack, Not an Exfiltration Attack
Most security tooling is built to detect exfiltration: data leaving the system, anomalous outbound network requests, unexpected API calls. The crypto wallet substitution technique is different in kind.
The user enters a wallet address. The script detects it, replaces it in the DOM with an attacker-controlled address. The user sees what they typed. The transaction is submitted. The funds go somewhere else.
No anomalous outbound request. No visible error. No immediate indication that anything went wrong. The user discovers the theft when the funds don’t arrive – at which point the cause is unclear, the transaction is irreversible, and the window for tracing the attack has often closed. Network monitoring would not reliably surface this. The manipulation happens inside the page, not across the wire.
This is compounded by how the AppsFlyer payload handled detection avoidance: console output suppressed, DOM mutation observers active, anti-forensics via element removal. A developer with tools open during the incident window would have seen nothing unusual.
The implication for incident response: if you served the compromised SDK during the exposure window and your users make cryptocurrency transactions, the question isn’t just whether data was exfiltrated – it’s whether any wallet substitutions occurred. Those events don’t show up in traditional data loss monitoring.
SRI: The Defence That Exists and Isn’t Used
Subresource Integrity (SRI) is a browser security feature that lets you specify a cryptographic hash for any external script tag. If the fetched resource doesn’t match the hash, the browser refuses to execute it. The syntax looks like this:
<script
src="https://websdk.appsflyer.com/loader.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..."
crossorigin="anonymous">
</script>
Had sites loading the AppsFlyer SDK used SRI with a hash of the known-good script, every browser would have refused to execute the substituted payload. The attack would have been blocked at the browser level, before any malicious code ran.
The defence is well-supported – all modern browsers implement it. It would have worked here. Almost nobody was using it.
The reasons for low SRI adoption on third-party analytics and attribution SDKs are structural:
Vendors update their SDKs frequently, often without announcing specific version changes or publishing hash values. The integration documentation for most analytics tools shows a bare script tag with no integrity attribute – because that’s what works without any additional setup, and because locking to a specific hash immediately breaks when the vendor ships an update. Most SDK vendors don’t provide hash values at all, much less in a format that integrators can consume programmatically.
There’s also a meaningful operational cost. Deploying SRI for a frequently-updated third-party SDK means either: accepting script failures when the vendor updates without notice (because the hash no longer matches), or building a monitoring and update process to track new SDK versions and update your hash values before vendor deployments. Neither is trivial at scale.
The result is a rational but collectively terrible equilibrium. Every site has a legitimate reason not to use SRI for their attribution SDK. The aggregate effect is that millions of sites have no browser-level protection against exactly this attack.
For high-sensitivity pages – payment flows, wallet connection screens, anything that handles transaction amounts or addresses – the calculus changes. The cost of SRI operational overhead is lower than the cost of a 14-hour window where every user transaction is being intercepted.
PCI DSS 4.0.1 Requirements 6.4.3 and 11.6.1 require continuous inventory and integrity monitoring of scripts on payment pages precisely because of this attack pattern. If you’re in scope for PCI DSS, this isn’t optional.
What to Do Now
Check whether you load the AppsFlyer Web SDK. Not just on marketing pages – check your full page inventory, including checkout flows, wallet connection screens, and any page that handles payment events. The SDK is often added by a marketing team and not fully tracked by engineering.
Review telemetry for the exposure window. The confirmed window is March 9 20:40 UTC to March 10 10:30 UTC. Check CDN and server logs for SDK loads from websdk.appsflyer.com during that period. If you served the SDK to users during that window, treat those sessions as potentially compromised.
Assess your payment architecture. Cross-origin payment iframes (Stripe Elements, Braintree, Adyen, and similar) are protected by the browser’s same-origin policy – the payload cannot reach across that origin boundary. Same-origin payment handling is not protected.
Audit your third-party JS inventory. The AppsFlyer incident will not be the last one. Build an inventory of every third-party script tag on your production pages. Identify which load from vendor CDN domains rather than your own infrastructure. Understand which pages each one appears on, and what data those pages handle.
Consider SRI for payment-adjacent pages. Start with the high-sensitivity surfaces: checkout flows, any page that displays or accepts cryptocurrency addresses, wallet connection screens. Implement a process to track SDK version updates and update hashes. It’s operationally annoying. It would have blocked this attack entirely.
Tighten Content Security Policy. A strict script-src directive restricts which origins can load scripts. A connect-src directive limits which origins scripts can make network requests to. Neither is a complete defence against a compromised SDK that’s already whitelisted, but both reduce the blast radius.
Request forensic transparency from AppsFlyer. The network interception infrastructure in the payload had significantly broader capabilities than crypto wallet substitution alone. Every fetch and XHR request on affected pages flowed through attacker-controlled proxy functions. Ask AppsFlyer: what was the C2 endpoint, was data exfiltrated from your domain, and did the C2 serve different configurations to different site domains?
Closing
The 14-hour incident is resolved. The AppsFlyer SDK is clean. The attack surface that made it possible is unchanged.
Domain registrar security is not where most engineering security programmes focus. Third-party JS SDKs served from vendor CDN domains sit in an interesting gap – too trusted to treat as untrusted third-party code, too far outside your control to treat as your own. That gap is where this attack lived.
SRI exists specifically to close it. The defence is deployed. The industry hasn’t adopted it for the cases where it matters most. The next attack on a widely-deployed analytics SDK will find the same situation.
The question isn’t whether this happens again. It’s whether you’re still loading scripts without hashes when it does.
For broader context on the multi-vendor trust chain this incident fits into, see The Cascade Problem. For supply chain attacks at the package registry layer – a different vector, the same underlying pattern – see Rust crates and CI/CD and PhantomRaven npm. For trust boundary design in systems that ingest third-party inputs, see Agent Pipeline Hardening.