You have found a script on your checkout that should not be there. Before you remove the Magecart skimmer, understand what you are actually removing: in most cases the thing you can see is a loader, a few lines of JavaScript whose only job is to fetch the real code from somewhere else. Delete it and the page looks clean. The foothold that put it there is still on your server, in your database, or in the hands of someone with a working admin login.
That is why clean-ups fail. A file-only tidy-up commonly reinfects within days, usually on the next cache flush or the next cron run. The runbook below is timed to 72 hours because that is the window UK GDPR gives you to notify the Information Commissioner’s Office of a personal data breach, and because an acquirer will start asking questions long before day three.
Hour 0 to 1: contain the bleeding, delete nothing
Stop the card capture first. The fastest honest option is to take the payment step out of your own page: switch to your payment provider’s hosted payment page or hosted fields, or put the checkout behind a maintenance notice. Both cost you orders. A live skimmer costs you every card typed while you investigate, and every one of those cards is a card your acquirer will later assume was taken.
Now preserve the scene. Before any file is edited, take a forensic snapshot:
- A full copy of the web root and application directories, with timestamps intact (an archive that preserves mtime, not a drag-and-drop copy).
- A complete database dump.
- Web server access and error logs, application logs, admin login logs, and any WAF or CDN logs. Pull them before rotation drops the oldest ones.
- A browser HAR file of the compromised checkout, plus a saved copy of the rendered HTML, so you have the page as a customer’s browser actually received it.
Hold the snapshot somewhere outside the compromised environment. Freeze deployments. And resist the urge to rotate every password in the first hour, because the credential in use is part of your evidence trail; change it now and you lose the ability to tie a session in the access log to the account that created the malicious CMS block.
One decision belongs in this hour and nowhere later. Ring your acquirer or payment service provider and ask whether they will require a PCI Forensic Investigator. If they will, everything you touch from that point needs to survive someone else’s review. Merchants who spend the first hour scrubbing files are the ones who cannot later tell an investigator when the exposure started, and an unbounded window means a larger assumed set of compromised cards.
Hours 1 to 12: find every copy, not just the one you spotted
Magecart is a label for a method, not a single crew, so there is no universal indicator list. Two stores can serve an identical payload and have completely different entry routes. Work from the browser inwards.
Start with what the page loads
Open the checkout in a clean browser profile with the network panel recording. Sort by domain. You are looking for scripts served from hosts nobody on your team can name, inline blocks that do not exist in your templates, scripts appended to the DOM at runtime rather than present in the source, and listeners bound to the card number, expiry and CVV fields. Repeat it on the guest checkout and the failed-payment retry path. Skimmers are often bound to a single route, and a payload that only fires on the second attempt is common enough to be worth testing deliberately. If you need the method in more detail, the walkthrough on detecting a skimmer on your website in about an hour covers the browser checks without special tools.
Then search the database, not only the filesystem
This is the step most guides skip, and it is the one that decides whether your clean-up holds. On Magento and Adobe Commerce, look at CMS blocks and pages, layout XML updates, widget instances, the design configuration for header and footer scripts, transactional email templates, and the core_config_data table. On WooCommerce, check post content, options, and any plugin that injects header or footer code. PrestaShop stores injected JavaScript happily in module configuration. A skimmer living in a database row survives a file restore and reappears the moment the cache regenerates.
Recognise the shape of the thing
Typical structures are easy to spot once you know them. A two-line loader that builds a script element and points it at a domain that looks almost like your CDN or your analytics vendor. Long base64 or hex strings passed through atob or a custom decoder. String concatenation used to hide a URL. Exfiltration to a lookalike host, sometimes to an image endpoint, sometimes carried in a WebSocket. Read the decoded payload rather than guessing; the exfiltration domain in it is also the search term that finds the other copies.
Finally, compare files against a known-clean release of your exact platform version, or against your Git repository, and diff the whole tree. Plugin scanners match signatures. Skimmer code is frequently rewritten per victim, so a clean scan report means little. A diff against a clean release does not care what the code looks like.
Hours 12 to 36: remove the Magecart skimmer and close the persistence
Restore, do not hand-edit. Replace modified core, vendor and theme files from a clean release or from version control rather than snipping out the lines you can see. Hand-editing leaves the parts you did not find.
Then go hunting for the way back in:
- Admin users created or modified since the first suspicious log entry, and any that authenticate from unusual addresses. Check API users, integration tokens and OAuth keys too.
- Scheduled tasks: crontab entries for the web user, application cron jobs, and any queue consumer that executes code from a database field.
- Web shells in writable directories: media, var, pub/static, uploads, tmp. Look for PHP files where only images should be, and for files with recent mtimes inside otherwise static folders.
- Malicious or abandoned modules and plugins, including ones that look legitimate but were installed outside your normal process.
- Database triggers and stored procedures that rewrite content on insert or update. Rare, but they defeat every file-based clean-up.
Patch the route in before you reopen: platform and extension updates, admin panel exposure (IP restriction, VPN, a non-default path, two-factor enforced), and the credentials of any third-party supplier or agency whose access was used. If the malicious script came from a supplier’s own infrastructure, none of this applies to you and the only fix is on your page, which is covered further down.
Rotate credentials now, in order: admin passwords and two-factor secrets, API and payment gateway keys, database users, SSH keys and deploy keys, then invalidate every session and cookie. Rotating in the wrong order simply hands the attacker the new keys through a session you have not yet killed.
Hours 36 to 60: prove it has gone, and prove it stays gone
Retest the live checkout from a clean browser profile, then on a real mobile device, then through guest checkout and a deliberately declined card. Compare the network waterfall against the list of scripts you have decided belong there.
Then make the page tell you if it changes again. Deploy Content-Security-Policy-Report-Only on the payment page with a reporting endpoint, leave it for one to two weeks, and read what arrives. You will find legitimate scripts you had forgotten about. Once the reports are quiet, enforce a named script-src allow-list. The working CSP setup for a checkout page explains the directives worth setting and the ones that break payment iframes.
Pin the third-party files you cannot control with Subresource Integrity hashes, and accept the maintenance: when the supplier ships an update, the hash stops matching and the script stops loading. That is the mechanism working. Put someone’s name against it so an expired hash does not silently break your basket on a Saturday.
Moving card inputs into hosted payment fields or a provider iframe is the strongest structural change available, and it is not a removal step. It narrows what a future injection can read. It does nothing for names, delivery addresses, order contents, or an attacker drawing a convincing fake payment form on top of the real iframe.
Hours 60 to 72: who you must tell
Acquirer and payment provider first. They carry the card scheme obligations and will route them to you. Expect requests for the transaction window, the affected BIN ranges or card count, and your evidence package. Give them the snapshot, not a summary.
Under UK GDPR, you have 72 hours from becoming aware of a personal data breach to notify the ICO where there is a risk to people’s rights and freedoms, and a separate duty to tell affected customers without undue delay where the risk to them is high. Card details taken at the point of entry clear that bar comfortably. The ICO’s personal data breach reporting guidance sets out what a report must contain, and an incomplete report filed on time is better than a perfect one filed late.
There is a compliance tail as well. PCI DSS 4.0 requirements 6.4.3 and 11.6.1 have been mandatory since 31 March 2025. Between them they ask for an inventory of every script on the payment page with a written justification for each, authorisation for those scripts, and detection of unauthorised change to payment page headers and content. A clean-up that leaves neither behind will fail your next assessment even if the site is spotless. The cheap way to satisfy both: keep the script inventory in version control alongside the code, keep the CSP reporting endpoint you just built, and run a nightly hash of the rendered payment page HTML and headers with an alert on change. That is what 6.4.3 and 11.6.1 actually ask of a payment page, without buying a product.
Why skimmers come back, and the three routes to shut
Reinfection is almost always one of three things, and the recorded incidents follow the same three routes in.
Supplier code. Ticketmaster UK, June 2018: the skimming ran through a compromised third-party chat widget supplier, and the malicious code never sat on Ticketmaster’s servers. A merchant cannot remove that code. A merchant can stop loading it, allow-list it away with CSP, or pin it. A chat widget has no business on the page where card numbers are typed.
First-party code. British Airways, August to September 2018: a script the airline owned and served was modified. The fix is file integrity, controlled deployment, and knowing which files the payment page loads.
Unpatched platform. September 2020: Sansec reported roughly 2,000 Magento 1 stores compromised over a single weekend, months after the platform reached end of life. On unsupported software, reinfection is a matter of when.
Give yourself a 30-day follow-up list: weekly log review for admin creation and unusual authentication, an extension audit with anything unused removed, a hard restriction on who can deploy to the payment page, and a monthly read of the CSP reports rather than filing them unread.
The short version
Contain, then snapshot, then investigate, then clean. Search the database as well as the files. Assume the visible script is a loader and that the real foothold is an account, a cron entry, a module or a CMS block. Rotate credentials after you have the logs, not before. Notify your acquirer immediately and the ICO within 72 hours where the breach warrants it. Then leave behind a script inventory, a CSP allow-list and page change detection, because that is the difference between having managed to remove a Magecart skimmer once and not having to do it again in a fortnight.
Frequently Asked Questions
How do I remove a Magecart skimmer without destroying the evidence my acquirer needs?
Take the payment page out of service first, then copy the file system with timestamps intact, dump the database, and export web server, application and admin login logs before you edit a single file. Save a HAR file of the compromised checkout as well. Only then start removing code, and keep the snapshot outside the compromised environment in case a PCI Forensic Investigator is appointed.
Why did the skimmer come back a few days after I deleted it?
Because the file you deleted was not the infection. The usual survivors are a rogue admin account, a cron entry, a malicious module, a web shell in a writable directory, or a CMS block in the database that rewrites the page on the next cache flush. Until the persistence mechanism and the original entry route are both closed, the payload simply returns.
Do I have to take my checkout offline while I clean it?
You have to stop cards being captured, which is not quite the same thing. Switching card entry to your provider’s hosted payment page or hosted fields usually keeps you trading while removing the data the skimmer wants. If that is not available quickly, take the payment step down; a live skimmer expands the exposure window every hour it runs.
Who do I have to notify after a card skimmer is found on my payment page?
Your acquirer and payment service provider first, since card scheme reporting flows through them and they decide whether a forensic investigator is required. Then the ICO, within 72 hours of becoming aware, where the breach poses a risk to individuals, and affected customers directly where the risk to them is high. Card data captured at entry normally meets that threshold.
Will a malware scanner or security plugin find a Magecart skimmer?
Sometimes, and not reliably. Skimmer code is often rewritten or obfuscated per victim, and much of it lives in database rows rather than files, which many scanners never read. Diffing your installation against a clean release of the same version, plus reading what the checkout actually loads in a browser, finds more than a signature scan does.
