PrestaShop store hacked: what to do in the first hour
In short
If your PrestaShop store is hacked, in the first hour you test the checkout (a skimmer may be stealing cards) and disable that payment method if in doubt, copy the files, database and logs as they are, and change the passwords, without deleting anything blindly. Then you look for modified files, overrides, hooks and ps_configuration values, and the module they got in through. If customer data was affected, the GDPR gives you 72 hours to notify your data protection authority.
I work with PrestaShop every day, and almost every hacked store I see has two things in common: an outdated third-party module and nobody watching which files change. This guide is what I would do, in order, if the store were mine.
By Jose SorianoLast updated: 8 min read
The first hour
- Check the checkout. Place a test order and watch the payment step: does a card form appear on your own page when your payment gateway normally redirects or shows its own? Is there an extra step, or an error after entering the card followed by the "real" payment? If you suspect a skimmer, disable that payment method while you investigate. Every order placed with the skimmer active is a stolen card.
- Take a full backup of the files and database as they are. Also save the server's access logs: some hosts only keep a few days. It's your evidence and your way back.
- Change the passwords: hosting, FTP, database, back-office employees and the payment gateway account. From a clean computer. If you change the database password, update it in
app/config/parameters.php(1.7, 8 and 9) so the store doesn't go down. - Don't delete anything yet. What you find tells you how they got in.
- Write down dates: when the complaints or fraudulent charges started. You'll need them for the bank and, if it applies, for the GDPR.
How they usually get in: real cases
It's worth knowing the documented patterns, because they repeat. Every one I mention has a public advisory and a link to the source.
The blm.php campaign (2022)
In July 2022, the PrestaShop team warned about a campaign that chained an SQL injection (in a module or in the core itself) with Smarty's MySQL cache feature to execute code. The pattern in the logs was a POST request to the vulnerable endpoint, a GET / one second later and then requests to a new file, blm.php, in the root. With that control, the attackers injected a fake payment form into the checkout. It was fixed in PrestaShop 1.7.8.7 as CVE-2022-31181 (critical, 9.8).
The same advisory pointed out that versions 2.0.0 to 2.1.0 of the blockwishlist wishlist module were vulnerable to SQL injection (CVE-2022-31101).
Third-party modules with SQL injection or file upload flaws
The Friends of Presta association publishes security advisories for modules, and several of them state explicitly that the flaw is being used to install skimmers: for example, the Stripe payment module stripejs before 4.5.5 (CVE-2023-23315), the simpleimportproduct importer up to 6.7.0 (CVE-2024-25846) or the one-page checkout supercheckout up to 6.0.6 (CVE-2023-45384). I keep a longer list in PrestaShop modules with known vulnerabilities.
One important detail from those advisories: many attacks use a module controller and hide the path, so in the normal log you'll only see POST /. Not seeing the module's name rules out nothing.
Where to look
Recently modified files
With SSH access, from the store's root. These commands only read; they don't change anything:
# PHP files modified in the last 15 days (excluding the cache)
find . -name "*.php" -mtime -15 -not -path "./var/cache/*" -printf "%TY-%Tm-%Td %TH:%TM %p\n" | sort -r | head -50
# PHP files in folders that shouldn't have any (except the protective index.php files)
find img upload download -name "*.php" ! -name "index.php"
# Functions typical of obfuscated code
grep -rlE "eval\(|base64_decode\(|gzinflate\(|str_rot13\(" --include=*.php . | grep -vE "^\./(vendor|var/cache)/"The last command gives false positives: some legitimate libraries use those functions. What you're looking for is store or module files that didn't use them before, or that have absurdly long lines that make no sense. Modification dates can also be faked, so don't rely on them alone.
Modified core files
PrestaShop skimmers tend to touch files involved in the order: classes/Cart.php, classes/PaymentModule.php, checkout controllers or the payment step template. The reliable way to find them is to compare every file with the original from your exact version of PrestaShop (downloaded from the official website or its GitHub repository). The read-only connector does that comparison file by file.
The override/ folder
Overrides let a module or a developer change the core's behavior without touching it. They're legitimate, but also a good hiding place. Check every file in override/classes/ and override/controllers/: you should know which module or developer created it. After changing anything there, delete var/cache/ (or cache/class_index.php on 1.6) so PrestaShop reads it again.
Modules
Look in modules/ for folders you don't recognize and recent modification dates. Above all, check the version of each third-party module against the published advisories: a module with a known flaw is the most common way in. A disabled module is still on the server and its files still respond, so it counts too.
Database: configuration, hooks and employees
From phpMyAdmin or the MySQL console. Replace ps_ with your prefix if it's different (it's in app/config/parameters.php):
-- Scripts stored in the configuration
SELECT name, LEFT(value, 120) FROM ps_configuration
WHERE value LIKE '%<script%' OR value LIKE '%eval(%' OR value LIKE '%atob(%';
-- Smarty cache type: if it's 'mysql' and you didn't set it, that's a bad sign
SELECT name, value FROM ps_configuration WHERE name = 'PS_SMARTY_CACHING_TYPE';
-- Which modules hook into the header, the footer and the payment step
SELECT h.name AS hook, m.name AS module_name, m.version, m.active
FROM ps_hook_module hm
JOIN ps_hook h ON h.id_hook = hm.id_hook
JOIN ps_module m ON m.id_module = hm.id_module
WHERE h.name IN ('displayHeader', 'actionFrontControllerSetMedia',
'displayBeforeBodyClosingTag', 'paymentOptions', 'displayPaymentTop')
ORDER BY h.name, hm.position;
-- Back-office employees
SELECT id_employee, email, firstname, lastname, active FROM ps_employee;In the hooks query, any module you don't recognize hooked into displayHeader or the payment step deserves a look at its folder. Also search for <script in the CMS pages (ps_cms_lang) and in custom HTML block modules.
Scheduled tasks and server access
Check the hosting user's cron jobs (crontab -l or the Cron section of the control panel) and PrestaShop's own if you use a scheduled tasks module. A task that downloads a file from an unknown domain or runs a strangely named PHP file is the typical way an infection comes back. Also check the FTP accounts in the panel and the keys in ~/.ssh/authorized_keys: any access nobody can explain goes.
Access logs
Look for POST requests to files inside modules/ or to PHP files in the root that you don't know, and the requests right after them:
grep -E "POST /modules/|POST /[a-z0-9_-]+\.php|blm\.php" access.log | tail -50Dangerous configuration
_PS_MODE_DEV_set totruein production (config/defines.inc.php): it shows errors with internal paths and data.- The admin folder with an easy-to-guess name.
- The
install/folder not deleted after installation. .zipor.sqlbackups in the root or in public folders.
Before you reopen
When you think it's clean, check it the way a customer would, not as an administrator: a complete test purchase from a browser with no session, with the developer tools open on the Network tab to see which domains the payment step connects to. Repeat the file and database searches above: nothing new should come up. And keep some way of monitoring file changes active for the following weeks, because if a backdoor was left behind it will show soon.
If customer data was affected
If the attack may have exposed personal data (names, addresses, emails, let alone cards), the GDPR requires the data controller, that is you, to notify the supervisory authority without undue delay and, where feasible, within 72 hours of becoming aware of it, unless it's unlikely to result in a risk to people. For a store based in Spain that's the AEPD (Spain's data protection authority); elsewhere in the EU, your country's supervisory authority. If the risk is high, you also have to inform the people affected. I explain it in detail in data breach in your online store.
If cards were stolen, also tell your payment gateway or your bank: they have procedures for these cases. Check the legal side with your lawyer or advisor; the technical side (what data, since when, how they got in) is what the cleanup report should tell. How to detect a skimmer and where it hides is in credit card skimming in your store.
How to keep it from happening again
- Update the core and the modules. PrestaShop 1.7 stopped receiving patches when version 9.0 came out; if you're still on 1.7 or 1.6, plan the move. I explain it in upgrading PrestaShop.
- Remove the modules you don't use, even if they're disabled: their files are still on the server and may be exploitable.
- Monitor file integrity. Finding out the next day that someone touched
classes/Cart.phpis the difference between a scare and months of stolen cards. - Review the back-office employees and use long, different passwords for each one.
- Keep backups off the server and check every now and then that they can be restored.
If you'd rather I fix it
Cleaning up a PrestaShop store costs €349 excluding VAT. I start by stopping the leak at the checkout, review the core, overrides, modules and database, close the way in and hand you a technical report you can use with your bank and for GDPR purposes. It comes with a 90-day guarantee. If you need it to take priority over my other work, priority is added for +€100 excluding VAT. More details in hacked PrestaShop repair.
Sources
- PrestaShop: advisory on the July 2022 campaign (SQL injection chain with Smarty's MySQL cache,
blm.php, fake payment form,blockwishlist2.0.0 to 2.1.0 and the fix in 1.7.8.7). - PrestaShop core advisory GHSA-hrgx-p36p-89q4 (CVE-2022-31181, critical, 9.8, fixed in 1.7.8.7).
- NVD: CVE-2022-36408 (rejected as a duplicate of CVE-2022-31181 because of a typo).
- Friends of Presta: advisories for stripejs, simpleimportproduct and supercheckout (modules used to install skimmers).
- PrestaShop 1.7.8 in extended support (security maintenance for 1.7.8 ends with the release of PrestaShop 9.0.0).
- Regulation (EU) 2016/679, GDPR, Articles 33 and 34 (EUR-Lex) and AEPD: personal data breach notification (72-hour deadline; in Spanish).
Frequently asked questions
Does restoring an older backup work?
Only if you know the backup predates the intrusion and you then fix the flaw they got in through. Otherwise it happens again.
Do I have to tell my customers?
If the breach is likely to result in a high risk to them (for example, exposed cards or passwords), the GDPR requires you to inform them. Decide with your advisor, with the technical report in front of you.
What is blm.php in PrestaShop?
It's the name of the file that the attackers in the July 2022 campaign (CVE-2022-31181) left in the store's root to execute code and insert a fake payment form. If you find it, the store is compromised even if you've already updated.
How do I know which module they got in through?
By matching each module's version against the published advisories and checking the access logs around the dates of the attack. If the logs only show “POST /”, the attacker hid the path and the modules have to be reviewed one by one.