← Back to blog

Magento 2 Malware Cleanup Checklist for Store Owners

Rodrigo Biazzi

A compromised Magento store usually does not look broken. The most common malware on ecommerce sites is a payment skimmer: a few lines of JavaScript that copy card data from the checkout form and send it somewhere else. The store keeps selling, and the owner finds out weeks later from the payment provider, a bank or a customer.

This checklist is for store owners and developers who suspect a compromise. It covers how to confirm it, how to clean up in a way that does not leave a back door behind, and how to harden the store afterwards. It is not a replacement for a professional incident response when card data is involved, but it describes the work that has to happen either way.

Signs that something is wrong

  • The payment provider or acquiring bank reports fraud linked to your store
  • A security scanner, such as Adobe's free Security Scan Tool, reports malware or a known skimmer
  • Admin users you do not recognize, or integrations nobody created
  • Unexpected JavaScript loaded on checkout from a domain you do not know, visible in the browser developer tools network tab
  • New PHP files in folders that should only hold images or static files
  • Server load or outgoing traffic that does not match normal store activity

Any one of these is enough to start the process below. Do not wait for a second sign.

1. Contain before you investigate

If the skimmer is live, every order exposes another customer. Decide quickly whether to put the store in maintenance mode or to disable card payments until the cleanup is done. That is a business decision, but it should be made in hours, not days.

Then preserve evidence before changing anything:

  • A full copy of the code folder, including vendor, generated and pub
  • A database dump
  • Web server access logs and PHP logs for as far back as they go

Store these copies outside the server. You will need them to find the entry point, and you may need them for your payment provider or for a forensic investigator. If card data was involved, contact your payment provider early. PCI DSS and privacy laws such as GDPR can require formal notification within strict deadlines.

2. Find what changed in the files

If the project is in Git, the fastest check is to compare the server with the repository:

cd /var/www/shop
git status --porcelain
git diff --stat

For vendor, compare against a fresh install. Run composer install into a separate clean folder from the same composer.lock and compare:

diff -rq /tmp/clean-build/vendor /var/www/shop/vendor

Without Git, look for files that should not exist and recently modified PHP files:

find pub/media pub/static var -type f -name "*.php"
find app pub vendor -type f -name "*.php" -mtime -30 -printf "%TY-%Tm-%Td %p\n" | sort
grep -rlE "eval\(|base64_decode\(|gzinflate\(|str_rot13\(" app/code pub --include=*.php

The grep will match some legitimate code, so read each hit before deciding. Attackers also change file timestamps, so a file that looks old is not proof that it is clean. This is why rebuilding from a known source in step 4 matters more than finding every file.

Check places outside the web root too: the crontab of the web user, files in the home directory, and any startup scripts. Reinfection through a scheduled job is a common reason a cleaned store gets infected again.

3. Find what changed in the database

Many skimmers live only in the database, because no file scan finds them there. The usual places are configuration fields that render HTML and CMS content.

SELECT config_id, scope, scope_id, path
FROM core_config_data
WHERE value LIKE '%<script%' OR value LIKE '%eval(%' OR value LIKE '%atob(%';

SELECT block_id, identifier, update_time
FROM cms_block
WHERE content LIKE '%<script%';

SELECT page_id, identifier, update_time
FROM cms_page
WHERE content LIKE '%<script%';

Pay special attention to the design settings for the HTML head and footer, which are stored in core_config_data under paths starting with design/. Some stores legitimately add tracking scripts there, so compare each result against what the marketing team knows they added.

Then check access:

SELECT user_id, username, email, created, logdate, is_active FROM admin_user;
SELECT integration_id, name, email, status, created_at FROM integration;

Delete admin users and integrations that nobody can explain. Also check widget instances and email templates if your store customizes them, since both can hold markup.

4. Rebuild from a known clean source

Cleaning infected files one by one leaves a real chance of missing one. The reliable approach is to rebuild the code base:

  1. Start from your Git repository at a commit from before the compromise, or from a clean Composer install of the same versions.
  2. Review custom code in app/code and the theme against the repository. Anything not in version control needs to be read line by line or replaced.
  3. Run composer install to recreate vendor from the lock file.
  4. Regenerate generated code and static content with setup:di:compile and setup:static-content:deploy. Do not copy generated, pub/static or var from the old server.
  5. Copy pub/media only after checking it for scripts, and confirm the web server does not execute PHP from media.
  6. Deploy to a fresh server or a freshly installed one if you cannot rule out that the operating system itself was compromised.

5. Rotate every credential

Assume the attacker read app/etc/env.php. Change:

  • Database user password
  • All admin passwords, and reset 2FA for every admin user
  • Payment gateway API keys, shipping and ERP credentials, and any other secret stored in configuration
  • SSH keys, hosting panel and SFTP passwords
  • Integration and API tokens
  • The Magento encryption key, following Adobe's guidance for your version, because values encrypted with the old key were readable to anyone holding it

6. Close the entry point

A store that is cleaned but not patched will be compromised again, often within days. Use the logs you preserved to find how the attacker got in. The usual causes:

  • Missing Magento security patches. Upgrade to the latest patch release for your version. See the security patches guide.
  • A vulnerable third party extension. Update or remove it, and review the rest. The extension audit checklist covers how.
  • Stolen admin credentials without 2FA.
  • Weak server access: shared SSH passwords, exposed database ports, old control panels.

7. Harden and monitor

  • Deny PHP execution in pub/media and pub/static at the web server. The Magento Nginx sample config already does this, so check that your config still has it.
  • Restrict the admin by IP or VPN and keep two factor authentication on. See the admin hardening checklist.
  • Make code read only for the web server user in production, with writable access only for var, generated, pub/static and pub/media.
  • Add a Content Security Policy that restricts where checkout can load scripts and send data. Magento 2.4.7 and later enforce CSP on payment pages.
  • Monitor file changes and the configuration fields listed in step 3, and schedule regular external scans.

After cleanup, keep watching for a few weeks. If the same injection comes back, the entry point is still open.

FAQ

How do I know if my Magento store has a card skimmer?

Open the checkout with the browser developer tools and look for scripts or requests to unknown domains. Also search core_config_data and CMS content for script tags, and run an external malware scan.

Is it enough to delete the infected files?

Usually not. Attackers leave back doors in several places, including the database and cron. Rebuild the code from a clean source, clean the database and rotate every credential.

Do I have to notify anyone after a Magento breach?

If payment or personal data was exposed, PCI DSS and privacy laws such as GDPR can require notifying your payment provider, authorities and customers. Get advice early because deadlines can be short.

How did the attacker get in?

The most common causes are missing security patches, vulnerable extensions and stolen admin passwords. Check your access logs from before the infection date to find the exact entry point.

I am available for freelance Magento and Adobe Commerce work, including cleanup and hardening after a compromise. If you need help with this, get in touch.

Related articles