
A Magecart attack is a piece of JavaScript that someone has added to your store's checkout. It copies the card number, expiry date and security code as the customer types them and sends the data to a server the attacker controls. The order still goes through, the payment is authorised and the site stays up. Nothing in your order numbers changes. You usually hear about it weeks later, from your payment provider or from customers whose cards were used elsewhere.
To catch one, keep a written list of every script that loads on your checkout and payment pages. Then compare what a real, logged-out visitor's browser receives against that list at least once a week, and after every release. With Black Friday on 27 November 2026 and Cyber Monday on 30 November, there are about four weeks to set that up and run it a few times while traffic is still normal.
On 14 January 2026, Malwarebytes reported on a web-skimming operation that researchers at Silent Push had tracked since early 2022. Its scripts target American Express, Diners Club, Discover, JCB, Mastercard and UnionPay. According to that report, attackers inject JavaScript into legitimate checkout pages through supply chains, third-party scripts or the store itself. The code is heavily obfuscated, and it can remove itself from the page, so a store admin who looks at the checkout while logged in may see a clean page.
The card rules changed as well. In PCI DSS v4, requirement 6.4.3 says all payment page scripts that run in the consumer's browser must be managed: each script authorised, its integrity assured, and an inventory kept "with written justification as to why each is necessary". It covers scripts loaded from your own environment and from third and fourth parties. Requirement 11.6.1 asks for a change- and tamper-detection mechanism that alerts staff to unauthorised changes to the HTTP headers and contents of payment pages "as received by the consumer browser", run at least once every seven days or at a frequency set by a targeted risk analysis. Both were best practice until 31 March 2025 and have been required since.
In early 2025 the PCI Security Standards Council changed SAQ A, the short questionnaire many small stores use. Merchants who embed a provider's payment form (an iframe, for example) must now confirm their site "is not susceptible to attacks from scripts". FAQ 1588 says you can do that by applying techniques like 6.4.3 and 11.6.1 yourself or through a third party, or by getting confirmation from a PCI DSS compliant payment provider that its embedded solution includes such protections when you follow its instructions. Stores that redirect the customer to the provider's own page are outside this particular criterion. Confirm with your acquirer which questionnaire applies to you; this article is operational guidance, not compliance advice.
Peak season raises the stakes. Every extra checkout during Black Friday week is another card a live skimmer collects, and the code freeze many teams start in November leaves little room to investigate during it.
Map the pages in scope. Write down the URL of every page where a customer enters card data or that hosts the payment form: cart, checkout, the payment step, and any "pay for order" or invoice payment links. On WooCommerce this includes /checkout/ and the order-pay endpoint. On Shopify, the checkout itself is hosted by Shopify, but your theme, apps and pixels still run on the pages before it.
Record what loads, from a clean browser. Open a private window with no admin cookies. Ideally use a second device on a mobile network, because some skimmers hide from admin sessions. Add a product to the cart, go to the payment step, open developer tools and run the snippet from the artefact below. Save the output with the date.
Write the inventory. For each script, record the domain, who added it (theme, plugin, app, tag manager, agency), what it does and why the payment page needs it. Anything on the list without a reason is a candidate for removal from the payment step. Analytics, chat widgets, heatmaps and A/B testing tools rarely need to run where the card is typed.
Look for the classic signs. Check for scripts loaded from domains that imitate your own or a known library (yourstore-cdn.com, jquery-min.net), long base64 or hex strings in inline scripts, code that adds new input fields to the payment form, and requests to unfamiliar domains that fire when you leave a card field. In the Network tab, filter by Fetch/XHR and type a test card number into the form to see what leaves the page.
Check where scripts get injected. On WordPress and WooCommerce, look at header and footer injection settings in the theme and in "insert code" plugins, the tag manager container, and recently modified files in the theme and wp-content. On Magento, review the design configuration fields for HTML head and footer scripts and the CMS blocks shown on checkout. Every platform also needs a review of admin users created in the last 90 days.
Lock what you can. Pin third-party scripts you host or reference by URL with Subresource Integrity (an integrity hash plus crossorigin="anonymous"), so the browser refuses a changed file. Add a Content-Security-Policy-Report-Only header on payment pages listing the domains you expect. It blocks nothing at first, but it reports every script that breaks the list.
Schedule the comparison. Repeat step 2 at least weekly and after every deploy, plugin update or tag manager publish, then diff the result against the approved inventory. A new domain on the payment page means you stop and find out who added it.
| Risk | Owner | Check | Frequency |
|---|---|---|---|
| Unknown script on the payment page | Store owner or agency lead | Diff live script list against the approved inventory | Weekly and after every release |
| Tag manager adds a script to checkout | Marketing plus developer | Review container publish history; restrict tags on payment pages | Every publish |
| Third-party library changed at the source | Developer | Subresource Integrity on pinned files; CSP violation reports | Continuous reports, weekly review |
| Injected code in theme, CMS block or settings | Developer or agency | File and setting change review; new admin accounts | Weekly in peak season |
| Embedded payment form treated as "safe" | Store owner | Ask the payment provider for written script-attack protection details | Once a year and when the integration changes |
| Customer fraud reports after purchase | Support lead | Log reports of card misuse; escalate two or more within a short window | As reported |
Paste this into the browser console on the payment step, logged out, after the page has fully loaded. It lists every script element and every script the page fetched, including ones added later by other scripts.
// Payment page script inventory snapshot
(() => {
const tags = [...document.scripts].map(s =>
s.src ? s.src : `(inline, ${s.textContent.length} chars) ${s.textContent.slice(0, 60).replace(/\s+/g, ' ')}`
);
const fetched = performance.getEntriesByType('resource')
.filter(e => e.initiatorType === 'script')
.map(e => e.name);
const domains = [...new Set([...tags, ...fetched]
.filter(u => u.startsWith('http'))
.map(u => new URL(u).hostname))].sort();
console.log('Date:', new Date().toISOString(), 'Page:', location.href);
console.log('Script domains:\n' + domains.join('\n'));
console.log('All scripts:\n' + [...new Set([...tags, ...fetched])].join('\n'));
})();
Weekly test plan to go with it:
PAYMENT PAGE SCRIPT CHECK (store: ________ date: ________ by: ________)
[ ] Logged-out private window, second device on mobile data
[ ] Snapshot run on: cart / checkout / payment step / order-pay link
[ ] Domains compared with approved inventory (attach diff)
[ ] New or changed domains: ______________ owner confirmed: Y / N
[ ] Inline scripts with obfuscated strings: none / listed
[ ] Network tab: no unknown requests while typing test card data
[ ] CSP report-only violations reviewed since last check
[ ] Tag manager publishes since last check reviewed
[ ] New admin users since last check: none / listed
Result: CLEAN / INVESTIGATE / INCIDENT
If you host a script yourself, generate the Subresource Integrity hash with:
cat checkout-widget.js | openssl dgst -sha384 -binary | openssl base64 -A
Then add integrity="sha384-<output>" crossorigin="anonymous" to the script tag. Remember to update the hash when you update the file, or the browser will block it.
A WooCommerce store selling outdoor gear takes about 300 orders a day in normal weeks; the numbers here are illustrative. The agency runs the snapshot on 2 November and finds 14 script domains on the checkout page. Twelve match the inventory. One belongs to a review widget a marketer added through the tag manager in October; it has no reason to be on checkout, so the agency excludes it there. The last one is static-cdnjs-cloud.com, loaded by a short inline script in the footer injection field of an "insert headers and footers" plugin.
Nobody on the team recognises the domain. The plugin's setting was changed the same day a new administrator account appeared. The agency removes the account and the injected code, rotates admin passwords and API keys, takes a copy of the evidence first, and calls the store's payment provider the same day. Because the snapshot had been run weekly since mid-October, they can tell the provider the code appeared within a specific seven-day window, which narrows the set of affected orders.
Limitations: a weekly manual snapshot will miss a skimmer that appears only for some visitors, some countries or some hours. Subresource Integrity cannot protect scripts that change on purpose, such as some analytics loaders. Dedicated client-side script monitoring tools exist for continuous coverage; whether you need one depends on your volume and on what your acquirer expects.
Compare the scripts a logged-out browser receives on your payment page with a list of scripts you approved. Unknown domains, obfuscated inline code and requests that fire while you type card data are the usual signs. Card misuse reports from several customers who all bought from you are another.
It reduces the exposure, because card fields live on the provider's page or in its iframe. Scripts on your own pages can still interfere with the shopper before or around the payment step, so keep an inventory of what runs there. Ask your provider in writing what script-attack protections their integration includes.
Save evidence (the script, page source, timestamps, admin and access logs), then remove the code and the way it got in, such as a rogue admin account or a vulnerable plugin. Contact your payment provider or acquirer the same day, and get legal advice on notification duties in the countries where you sell.
Last reviewed: 2026-10-26
Related reading: if your checkout was hit by bots rather than a skimmer, see card testing attacks. For the wider problem of a site that looks healthy while compromised, read a website can return 200 OK and still be hacked. To decide what to change during the November freeze, see Black Friday code freeze: what to lock and what to patch, and to list every vendor that touches your store, use the ecommerce dependency map.
Pingvera does not inventory checkout scripts. It covers some of the surrounding steps from this article: it flags WordPress compromise signals and unexpected redirects to foreign domains, and it puts deploys and incidents on one timeline. When a new script shows up in your weekly check, that timeline shows which release or change came just before it. You can try it free on up to 5 sites.
Pingvera watches whether an online business actually works — uptime, checkout, orders, domain, SSL and server — and alerts you in Telegram, email or a webhook before a customer has to tell you.
Start freeRead next: Card Testing Attack: Detect and Stop It Before Black Friday · Ecommerce Checkout Friction Audit · Accidental Noindex: How Agencies Detect It Fast · Apple Pay Button Not Showing at Checkout: Fix List · Run a free site check.