When a Magento store is hacked, the attacker is almost always after one thing: card data at checkout. That changes the priorities compared with a hacked blog. The first job is to stop the skimmer from collecting more cards, the second is to keep evidence, and only then do you clean. The short version of my process: maintenance mode, a forensic backup, a systematic search of the database and the code for injected JavaScript and backdoors, a patch to the current 2.4.x security release, rotation of the encryption key and every credential, a call to your payment provider, and hardening so it does not happen again. This is the playbook I follow, with the queries and commands.
Signs your Magento store has been hacked
Magento malware is built to stay quiet. A skimmer that breaks checkout gets noticed; one that copies card numbers in the background can run for months. The signs I look for:
- Customers reporting fraud on cards they used only in your store, or your payment provider or acquirer contacting you about a common point of purchase.
- A fake payment form: card fields appearing on a checkout that normally redirects to a hosted payment page or uses the gateway’s iframe, or a payment step that asks for the card twice.
- Unknown JavaScript loading on checkout, often from a domain that imitates a real analytics, CDN or payment brand, or sending data over a WebSocket.
- Admin users you did not create, or new integrations under System → Extensions → Integrations.
- Odd orders: bursts of small orders or failed payments that look like card testing, or orders with strange text in address and name fields.
- Files you do not recognize in
pub/,app/codeorvendor, and cron jobs you did not add.
Like WordPress malware, Magecart skimmers often only activate on the checkout page, only for guests, or only for certain countries or user agents. “I checked the site and it looks fine” tells you very little.
Contain the damage and preserve evidence
Before any cleanup, I stop the bleeding and take a copy of the store exactly as it is:
# Take the store offline, allowing only your own IP
bin/magento maintenance:enable --ip=203.0.113.10
# Forensic copy of the database, as it is now
mysqldump --single-transaction --quick --routines --triggers magento_db | gzip > infected-db.sql.gz
# Forensic copy of the code, config and web server logs
tar -czf infected-files.tar.gz --exclude=pub/media/catalog --exclude=var/cache /var/www/magento
tar -czf logs.tar.gz /var/log/nginx /var/www/magento/var/logStore these copies off the server. They are what you, your payment provider or a forensic investigator will use to work out how long the skimmer was live and what it took. Do not “quickly fix” things before taking them, because every file you touch destroys a timestamp.
Then change the passwords that do not depend on the cleanup: hosting panel, SSH and SFTP, and your own admin account, from a computer you trust. Full credential rotation comes later, once the backdoors are gone; rotating before that just hands fresh secrets to whoever still has a way in.
Where Magento skimmers hide: the database
Most Magecart skimmer removal jobs start in the database, not the files, because the admin lets anyone with a login paste HTML and scripts into the storefront. The first place to look is core_config_data. The paths attackers favour are design/head/includes (the “Scripts and Style Sheets” field) and design/footer/absolute_footer, but any config value that ends up in the page can carry a script, and the same path can exist separately at default, website and store view scope. So I search every value, not just the obvious paths. Replace table names if your install uses a prefix:
-- Any config value containing a script, iframe or common obfuscation
SELECT config_id, scope, scope_id, path, LEFT(value, 200)
FROM core_config_data
WHERE value LIKE '%<script%' OR value LIKE '%<iframe%'
OR value LIKE '%atob(%' OR value LIKE '%eval(%'
OR value LIKE '%fromCharCode%' OR value LIKE '%WebSocket%';
-- The two classic injection points, at every scope
SELECT config_id, scope, scope_id, path, value
FROM core_config_data
WHERE path IN ('design/head/includes', 'design/footer/absolute_footer');
-- CMS blocks and pages
SELECT block_id, identifier FROM cms_block
WHERE content LIKE '%<script%' OR content LIKE '%atob(%';
SELECT page_id, identifier FROM cms_page
WHERE content LIKE '%<script%' OR content LIKE '%atob(%';
-- Admin accounts, newest first
SELECT user_id, username, email, created, logdate, is_active
FROM admin_user ORDER BY created DESC;
-- Cron jobs Magento has scheduled
SELECT job_code, COUNT(*) FROM cron_schedule GROUP BY job_code ORDER BY job_code;Some hits will be legitimate: Google Tag Manager, a chat widget, a cookie banner. Compare each script against what the business actually installed, and look at where it sends data. A skimmer usually waits for the checkout URL or payment fields, collects the form values and posts them to a third-party domain or opens a WebSocket. Also check widget instances and the CMS content of any page builder you use, since both store HTML.
For admin_user, delete accounts nobody can vouch for, and look at the roles in authorization_role too. For cron_schedule, every job_code should map to a module you know. An unknown job code points to malicious code registered in a module’s crontab.xml. Check the system crontab as well with crontab -l for the web and deploy users, because reinfection scripts like to live outside Magento entirely.
Clean the files: pub/, app/code and vendor
Once the database is clean, the backdoors are what bring the skimmer back. These are the checks I run from the Magento root:
# PHP files where there should be none, or very few
find pub/media pub/static -type f -name "*.php"
find pub -maxdepth 1 -type f -name "*.php" # compare with a clean install
# Recently modified files (adjust the window)
find app pub lib vendor -type f -mtime -30 -printf '%TY-%Tm-%Td %p\n' | sort
# Classic PHP backdoor patterns
grep -rlE "eval\s*\(\s*(base64_decode|gzinflate|str_rot13)|\\\$_(POST|GET|COOKIE|REQUEST)\s*\[.{0,40}\]\s*\(" \
--include=*.php app pub lib vendorpub/ is where skimmer JavaScript and web shells usually land: an extra file in pub/media, a modified pub/static bundle, or a changed pub/index.php or .htaccess. Treat pub/static as disposable: once the source is clean, delete it and regenerate it with setup:static-content:deploy.
For vendor, do not read through thousands of files. Build a clean copy from the same composer.lock in a separate directory and diff it against the live one. Any difference is either a patch you know about or something the attacker did:
mkdir /tmp/clean && cp composer.json composer.lock auth.json /tmp/clean/
cd /tmp/clean && composer install --no-dev --no-scripts --prefer-dist
diff -rq /tmp/clean/vendor /var/www/magento/vendorKeep auth.json private and delete the temporary copy afterwards, since it holds your repository keys. For app/code, app/design and app/etc, the equivalent is git status and git diff against the last known-good commit, if the store is in Git. If it is not, that is the first thing I change after the cleanup, because without it there is no reliable way to tell your code from theirs. Also read app/etc/env.php and app/etc/config.php for modules or settings nobody added.
A commercial scanner such as Sansec’s eComscan is a useful second opinion here, because it knows many current skimmer and backdoor signatures specific to Magento. I use a scanner as one input alongside the manual checks above, not as proof that the store is clean.
CosmicSting: why patching alone is not enough
CosmicSting (CVE-2024-34102) is an XML external entity flaw in Magento and Adobe Commerce, fixed in Adobe’s bulletin APSB24-40. It lets an unauthenticated attacker read files from the server, and the file they want is app/etc/env.php, because it contains the encryption key. With that key an attacker can forge admin API tokens and decrypt stored secrets, and combined with a separate glibc flaw (CVE-2024-2961) it was also used to run code on the server.
The key point: if a store was unpatched while CosmicSting was being exploited, applying the patch closes the hole but does not take the stolen key back. In that case I also:
- Rotate the encryption key. Recent 2.4.x releases provide
bin/magento encryption:key:change; older versions do it from the admin under System → Other Settings → Manage Encryption Key. Check Adobe’s documentation for your exact version first, because the tooling and what gets re-encrypted have changed between releases. Take a database andenv.phpbackup before running it. - Re-enter secrets stored encrypted in the database, such as payment gateway and shipping API credentials, and rotate them with the provider, since the attacker may already have decrypted them.
- Invalidate integration and API tokens. Delete integrations you do not recognise and reauthorize the ones you keep so they get new tokens.
Patch the store and rotate every credential
Whatever the entry point, the store has to be on a supported release with the latest Magento 2 security patch, meaning the most recent -p release of your 2.4.x line or a newer minor version. That is done with Composer on staging first; my Magento 2 upgrade guide covers the commands, extension compatibility and rollback, so I will not repeat them here. Update third-party extensions too, because a vulnerable extension is as good an entry point as a core bug.
Then rotate, now that the backdoors are gone: every admin password, the database password in env.php, SSH keys and SFTP accounts, Redis and search credentials if they are exposed, repository keys in auth.json, and every third-party API key the store holds. Remove SSH keys in ~/.ssh/authorized_keys that nobody can account for.
Card data: tell your payment provider
If a skimmer ran on your checkout, card data was probably taken, and that is not only a technical problem. Contact your payment provider or acquirer promptly and tell them what you found and roughly when it started. Under PCI DSS they may require a formal investigation, and they will tell you what they need. The forensic copies you took in the first hour are what makes that possible. Depending on where you and your customers are, data protection law may also require you to notify authorities or customers within a deadline; that is a legal question, so get proper advice rather than guessing.
Harden the store so it stays clean
Most of the Magento hacks I see come down to an unpatched store, a compromised admin login, or a vulnerable extension. The hardening I apply after a Magento malware removal:
- A custom admin URL:
bin/magento setup:config:set --backend-frontname=<something-unguessable>. It is not security on its own, but it removes the admin from automated scans. - Two-factor authentication:
Magento_TwoFactorAuthis enabled by default in 2.4. Never disable it to make logins easier. - Restrict the admin by IP at the web server, or behind a VPN, so a stolen password is useless from anywhere else.
- Remove unused admin users and integrations, and give each person their own account with the narrowest role that works.
- Production mode and read-only code:
bin/magento deploy:mode:set production, with code owned by a deploy user and onlyvar,generated,pub/staticandpub/mediawritable by the web server. Code changes arrive through a deployment pipeline, not SFTP. - Content Security Policy and payment page script controls: the
Magento_Cspmodule, configured with a whitelist of the domains you actually use. PCI DSS 4.0 requirement 6.4.3 asks merchants to authorise, justify and check the integrity of every script on payment pages, and recent 2.4 releases added stricter CSP and script integrity support on checkout to help with that. Check what your version supports. - A WAF in front of the store, for example Cloudflare, with rules that block known exploit patterns and protect the admin path. My server security hardening work covers this, together with the OS-level items in my Linux server hardening checklist.
- Monitoring: file integrity checks on
app,pubandvendor, an alert on new admin users and on changes to thedesign/*config paths, and an external check that watches the scripts loaded on checkout.
Building the deployment pipeline, file permissions and monitoring properly is the part most stores skip, and it is what I set up under DevOps consulting.
When to bring in help
Cleaning a hacked Magento store takes careful work: the skimmer is rarely in only one place, and the backdoor that put it there is what matters most. If you would rather hand it over, my Magento development service covers the full process: containment, the database and file cleanup, patching, key and credential rotation, and hardening. Small jobs are billed at $20/hour; a full cleanup gets a fixed price agreed in writing before I start.
Frequently asked questions
How do I know if my Magento store has a card skimmer?
Look for unexpected JavaScript on the checkout page, especially scripts from unfamiliar domains or obfuscated code, and search core_config_data, cms_block and cms_page for script tags. Customer fraud reports or a call from your payment provider are often the first sign, because skimmers are built not to break checkout.
Is patching Magento enough after a hack?
No. A patch closes the hole that was used, but it does not remove skimmers, backdoors or rogue admin users already in place, and it does not undo stolen secrets. After an exploit like CosmicSting you also need to rotate the encryption key, API tokens and every credential.
Can I restore a backup instead of cleaning Magento?
Only if you are sure the backup predates the infection and you close the entry point before going live. Restoring also loses every order and customer created since the backup, so in practice cleaning the current store is usually the better option.
Does a hosted payment page protect me from Magecart?
It reduces the risk, because card numbers are entered on the provider's page, but it does not remove it. A skimmer can still show a fake card form before the redirect, so script controls on checkout and a clean store still matter.
Do I have to report a Magento breach?
If card data may have been taken, tell your payment provider or acquirer, who will explain the PCI DSS process. Data protection law may also require notifying authorities or customers depending on where you operate, so get legal advice on that part.