Formjacking attacks the moment a customer trusts your checkout page most – right as they type their card number. The attacker doesn’t need to breach your database or find a SQL injection flaw. They just need to slip a few lines of JavaScript into the page that renders the payment form, and from that point on, every card entered gets copied straight to them, invisibly, while the transaction still completes normally.
What formjacking actually is
Formjacking is client-side skimming. Malicious JavaScript – injected into a checkout page or loaded from a compromised third-party script – hooks into form fields or listens for submit events, then exfiltrates the captured data (card number, expiry, CVV, billing address) to a server the attacker controls. The checkout still works. The order still goes through. The customer has no idea anything happened until the fraudulent charges show up three weeks later.
The name comes from Gemini Advisory and RiskIQ research around 2018, but the technique dates back further – it’s the web equivalent of a physical card skimmer clipped onto an ATM slot. Magecart is the umbrella term for the criminal groups running these campaigns, and they’ve hit British Airways (2018, ~380,000 payment records, £20 million ICO fine), Ticketmaster UK, Newegg, and thousands of smaller Magento and WooCommerce stores that never made headlines.
How the injection actually happens
Three paths account for almost all real cases:
Compromised admin credentials or CMS vulnerability: attacker gets into WordPress/WooCommerce or Magento admin, edits a template or plugin file directly, adds the skimmer script inline. This is the most common route for small and mid-size e-commerce sites still running outdated plugins.
Supply chain compromise: the skimmer isn’t on your server at all – it’s in a third-party JavaScript library your checkout page loads. A chat widget, an analytics tag, an A/B testing script, a font loader. Compromise the vendor once, and every site embedding that script gets the payload. The 2018 British Airways breach traced back to a single modified script; the 2021 incident involving a compromised analytics provider hit hundreds of downstream sites simultaneously.
Vulnerable checkout plugin: outdated Magento extensions (CVE-2022-24086 being a notable example) or abandoned WooCommerce payment plugins with known RCE or file-upload flaws give attackers a direct path to drop skimming code without ever touching admin credentials.
Why it’s hard to catch from the server side
Server logs look completely normal. The payment gateway sees a valid transaction. Your WAF sees a POST request that matches expected form fields. Nothing about the request itself is malicious – the theft happens in the browser, before the legitimate submission even fires, or as a parallel silent request to the attacker’s collection endpoint.
This is the myth worth busting directly: a lot of teams assume PCI DSS compliance and a web application firewall mean they’re covered against this. They’re not. PCI DSS SAQ A and A-EP reduce scope specifically because you’re not supposed to be touching raw card data server-side – but that same architecture is exactly what formjacking exploits. The card data never touches your server, so your server-side monitoring never sees the theft. PCI DSS v4.0’s requirement 6.4.3 (mandating a method to confirm scripts on payment pages are authorized) and 11.6.1 (deploying a change-detection mechanism for HTTP headers and script content on payment pages) exist specifically to close this gap, and both became mandatory as of March 31, 2025 for applicable merchants.
What actually detects it
Detecting formjacking means watching what loads and executes on the checkout page itself, not just what your server sends and receives.
Subresource Integrity (SRI) hashes on every third-party script tag stop a compromised CDN from silently swapping in malicious code – if the script’s hash doesn’t match what you specified, the browser refuses to run it. This only covers scripts you load with a static <script> tag with an integrity attribute; dynamically injected scripts bypass it entirely, which is why it’s one layer, not the whole answer. Locking down third-party scripts with SRI is worth doing even outside payment pages.
Content Security Policy with a strict script-src directive (avoiding unsafe-inline) blocks unauthorized inline scripts from executing at all, which stops the “attacker edited the template directly” path cold. Combine it with report-uri or report-to so violations get logged instead of silently blocked.
Regular diffing of checkout page source and script inventory. An experienced practitioner doesn’t just check that the checkout page loads – they diff the actual rendered DOM and script list against a known-good baseline on a schedule, because a one-character change to a minified JS file is invisible to a human eyeball but easy to catch with an automated hash comparison. This is precisely the kind of check that gets skipped after launch because “the page still works fine.”
Malware and file-integrity scanning on the CMS itself catches the injected files before they’ve been live long enough to harvest a meaningful volume of cards. Combined with periodic checks against known Magecart skimmer signatures and outbound-connection patterns, this closes the loop between “compromise happened” and “compromise detected.”
Common mistakes teams make
Treating checkout security as a one-time PCI audit item rather than a continuous check is the biggest one – skimmers get added between audits, not during them. Assuming a payment gateway iframe (Stripe Elements, Braintree hosted fields) makes the whole page immune is another; the iframe protects the field itself, but if the surrounding page is compromised, attackers can still overlay fake fields, redirect users to a cloned checkout, or capture data before it even reaches the legitimate iframe. Third, many teams monitor uptime and functional correctness of checkout but never monitor script inventory drift, so a skimmer can sit live for weeks – Magecart infections have historically averaged several weeks of dwell time before discovery, per multiple RiskIQ incident writeups.
Frequently asked questions
Does using a hosted payment gateway like Stripe or PayPal eliminate formjacking risk?
It significantly reduces it for the fields inside the gateway’s iframe, since that content is isolated from your page’s JavaScript. It does not eliminate risk on the surrounding checkout page, where attackers can still inject fake overlay fields, redirect traffic, or harvest data entered before the customer reaches the hosted fields.
Can a standard vulnerability scan detect an active formjacking skimmer?
A scan that checks server-side vulnerabilities, SSL/TLS configuration, and security headers won’t directly see injected client-side JavaScript unless it also inspects rendered page content and script inventory for known malicious patterns or unexpected changes. This is why checkout-page script monitoring needs to be a specific, ongoing check rather than assumed coverage from a general audit.
How quickly can a formjacking skimmer be removed once found?
Removal itself – deleting the malicious file or reverting the compromised template – usually takes minutes once identified. The harder part is confirming the entry point is closed (patched plugin, rotated admin credentials, removed vulnerable extension) and determining how many transactions were exposed during the dwell period, which typically requires reviewing logs going back to when the script inventory last changed.
Formjacking succeeds because it exploits the gap between “the transaction completed successfully” and “the transaction was actually secure” – two things that look identical from the server side. Baseline your checkout page’s script inventory today, add SRI and a strict CSP where you haven’t already, and put script-diffing on a recurring schedule rather than an annual one.
