How to Perform a Magento 2 Security Audit: A Step-by-Step Checklist for Store Owners
Hey — if you manage a Magento 2 store yourself (or collaborate closely with the tech person who does), this post gives you a practical, step-by-step checklist for running a security audit. Think of it as a friendly walkthrough you can use to verify that the server, Magento instance, and extensions aren’t leaving obvious holes. I’ll keep the tone relaxed and show real commands and code snippets so you can try things as you go.
This checklist covers the technical essentials: server configuration and hardening, file permissions, updates, auditing third-party extensions, defending against common attacks (XSS, SQLi, CSRF), real-time monitoring and intrusion detection, and finally a concrete post-audit plan for maintenance. If you prefer, follow the sections in order or pick the parts that worry you most.
Quick map: what you’ll do in this audit
- Prepare: backups, maintenance mode, and access controls
- Server configuration review (TLS, firewall, PHP, MySQL)
- File ownership & permissions check
- Magento updates, patches and dependency checks
- Third-party extension audit and vulnerability evaluation
- Protection against XSS, SQL injection, CSRF
- Set up monitoring and intrusion detection (fail2ban, Wazuh/OSSEC)
- Post-audit plan: runbook, scheduled maintenance, and preventive tasks
Before you start: preparation
Run this audit during a low-traffic window. Always take a full backup and, ideally, work on a staging clone if you’ll apply changes. At minimum, put the store into maintenance mode before making risky changes.
# Put Magento in maintenance mode
bin/magento maintenance:enable
# Take a quick DB dump and archive the pub, app, and vendor directories
mysqldump -u magento_user -p magento_db > /backup/magento_db_$(date +%F).sql
tar -czf /backup/magento_files_$(date +%F).tar.gz app pub vendor
Make sure you have emergency access to the server (SSH key) and that another admin account exists if your primary login gets locked out.
1) Server configuration checklist
This is the foundation. If the OS, web server, or PHP is misconfigured, Magento won’t be secure even if the application is tidy.
1.1 Verify TLS/SSL
Run an SSL check (you can use openssl locally) and make sure you only support modern TLS versions and strong ciphers.
# Quick TLS check (basic)
echo | openssl s_client -connect your-site.com:443 -tls1_2
# Check supported protocols (more thorough scanners exist externally)
Require HTTPS site-wide, set HSTS, and ensure certificates are valid and auto-renewed (use Let’s Encrypt or your CA’s automation).
1.2 Web server hardening (Nginx / Apache)
Ensure that debug pages are disabled, directory listings are off, and that the server returns minimal information in error pages.
# Example Nginx hardening snippets (add to server block)
server_tokens off;
client_max_body_size 20M;
# Disable .git and .env access
location ~ /(\.|composer\.|git) {
deny all;
}
# Recommended security headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy no-referrer-when-downgrade;
add_header X-XSS-Protection "1; mode=block";
For Apache, ensure ServerSignature Off and ServerTokens Prod are set.
1.3 Firewall and network
Limit SSH access (allow only admin IPs or use a VPN), block unused ports, and enable a host firewall (ufw, nftables, or iptables). If you run a web application firewall (WAF), ensure the rules are active.
# Example UFW commands
ufw allow OpenSSH
ufw allow 80,443/tcp
ufw enable
# Limit SSH to a specific IP (replace x.x.x.x)
ufw allow from x.x.x.x to any port 22
1.4 PHP configuration
Check PHP options: disable dangerous functions, set proper memory and execution limits, and ensure display_errors is off in production.
# php.ini suggestions (production)
display_errors = Off
log_errors = On
memory_limit = 2G
expose_php = Off
# disable dangerous functions
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec
Also, set proper PHP-FPM process owner matching the web server’s user and separate pools for different sites if hosting multiple stores.
1.5 Database (MySQL / MariaDB)
Ensure remote DB access is disabled or limited to known hosts. Use strong DB user passwords and remove root remote logins.
# Check current user grants inside MySQL
SELECT user, host FROM mysql.user;
# Example: create a dedicated Magento DB user with limited privileges
CREATE USER 'magentouser'@'localhost' IDENTIFIED BY 'strongpassword';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON magento_db.* TO 'magentouser'@'localhost';
FLUSH PRIVILEGES;
Enable MySQL’s slow query log and audit queries that look suspicious. Use database backups and test restores periodically.
2) File ownership and permissions
Many compromises occur because files are writable by the wrong user. Magento’s recommended approach is to make sure the web server user owns generated and var directories while keeping most files read-only.
# Typical ownership and permissions (adjust and )
sudo chown -R : .
sudo find . -type f -exec chmod 644 {} \; # 644 for files
sudo find . -type d -exec chmod 755 {} \; # 755 for directories
# Writable dirs for Magento 2
sudo chown -R : var pub/generated pub/static app/etc
sudo chmod -R g+ws var pub generated
# OR a recommended set from Magento docs (safe default)
find var vendor pub/static pub/media app/etc -type f -exec chmod u+w,g+w {} \;
find var vendor pub/static pub/media app/etc -type d -exec chmod u+w,g+w {} \;
Why this matters: if an attacker can write to app/code or app/etc, they can modify config or drop backdoors. Keep write permissions minimal and use deployment pipelines to update code rather than editing in-place.
3) Updates & patches
Magento core patches (including security patches) and PHP/library updates are crucial. Never postpone security updates indefinitely.
3.1 Check Magento version and patches
# Magento CLI shows version
bin/magento --version
# Composer shows installed Magento packages
composer show | grep magento
# Quick check for open security updates via Composer Audit (if using Composer v2)
composer audit
If composer audit returns vulnerabilities, review the advisory and upgrade the affected package. Test upgrades on staging first.
3.2 Keep third-party libs updated
Composer manages dependencies. Use a staging environment to run composer update and test before production deployment.
# Example upgrade workflow (on dev/staging)
composer update vendor/package --with-dependencies
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy
4) Audit third-party extensions and evaluate vulnerabilities
Third-party modules are a major source of vulnerabilities. Your job is to inventory, validate, and if necessary isolate or patch modules.
4.1 Inventory installed modules
# List modules via Magento CLI
bin/magento module:status
# Also check composer.json and composer.lock
cat composer.json | jq .require
cat composer.lock | jq '.packages[] | {name,version}'
Export a list of modules and their versions for later tracking.
4.2 Check sources and support
For each third-party module, ask:
- Is it from a reputable vendor?
- Is it actively maintained?
- Is there security information or reported CVEs for it?
4.3 Automated vulnerability checks
Use tools such as:
- composer audit
- Security scanners like OWASP ZAP for application-level testing
- Static analysis tools to search for dangerous patterns
Example: use grep or ag to find direct SQL calls or eval() usage in modules:
# Search for risky PHP functions in app/code and vendor
grep -R "eval\(|base64_decode|exec\(|shell_exec|passthru|system\(" app/code vendor || true
If a module contains obfuscated code (base64 or eval) and you don’t expect it, isolate and replace it immediately.
4.4 Disable or sandbox risky modules
When in doubt, disable non-essential modules until you can validate them:
# Disable a module
bin/magento module:disable Vendor_Module
bin/magento cache:flush
And keep an emergency plan: if a module must be removed, test removal on staging and then remove via composer to keep composer.lock consistent.
5) Protection against common attacks
I’ll cover practical checks and code examples for XSS, SQL injection, and CSRF — the most common vectors you’ll face.
5.1 Cross-Site Scripting (XSS)
Magento provides helpers to escape output. If you or a third-party module echoes raw user input into a PHTML template, it’s a red flag.
# BAD (vulnerable)
<?php echo $block->getData('user_comment'); ?>
# GOOD (escaped)
<?php echo $block->escapeHtml($block->getData('user_comment')); ?>
# For attributes
<?php echo $block->escapeHtmlAttr($someValue); ?>
Audit templates for direct echo usage and enforce escaping functions: escapeHtml, escapeHtmlAttr, escapeUrl, etc.
5.2 SQL Injection
Magento’s framework uses the DB adapter which supports parameterized queries. Avoid building queries by concatenation with user input.
# BAD (string concat, vulnerable)
$sql = "SELECT * FROM custom_table WHERE id = " . $inputId;
$result = $connection->fetchAll($sql);
# GOOD (parameterized)
$sql = "SELECT * FROM custom_table WHERE id = ?";
$result = $connection->fetchAll($sql, [$inputId]);
# Or using quoteInto
$sql = $connection->quoteInto("SELECT * FROM custom_table WHERE id = ?", $inputId);
$result = $connection->fetchAll($sql);
Scan custom modules for concatenated SQL and replace them with parameterized methods.
5.3 Cross-Site Request Forgery (CSRF)
Magento uses form keys to protect forms. Ensure that custom forms include the form key and that AJAX posts include it too.
# Include form key in templates
<input name="form_key" type="hidden" value="<?php echo $block->escapeHtml($block->getFormKey()); ?>" />
# For AJAX (JS) include form_key in POST
var formKey = window.FORM_KEY;
fetch('/your/endpoint', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ form_key: formKey, data: myData })
});
On the server side, ensure controllers extend the right class so Magento checks the form key automatically when needed, or manually validate $this->_formKeyValidator->validate($this->getRequest()).
6) Real-time monitoring and intrusion detection
Auditing once is not enough. You need ongoing monitoring for suspicious activity and a way to rapidly triage alerts.
6.1 Log centralization
Aggregate logs from web server, PHP-FPM, and Magento (system and exception logs). Ship them to a central logging platform (Elastic Stack, Splunk, or hosted alternatives).
# Example: tail Magento logs
tail -n 200 var/log/system.log
tail -n 200 var/log/exception.log
Look for repeated login failures, sudden spikes in exceptions, or unusual admin activity.
6.2 Fail2ban for brute force prevention
Protect SSH and Magento admin login endpoints by blocking repeated failed attempts. Create a jail for admin login or use the built-in auth logs if you proxy requests.
# Example jail.local snippet for SSH
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
# Example for Nginx auth failure (custom filter required)
6.3 IDS/Endpoint detection (Wazuh/OSSEC)
Install an IDS like Wazuh or OSSEC to detect rootkits, file integrity changes, and suspicious behavior. Configure alerts for changes to app/etc/env.php, cronjobs, and new PHP files in pub/.
6.4 File integrity monitoring
Calculate and monitor checksums of your codebase. If a file changes unexpectedly in production, trigger an alert and isolate the instance.
# Simple checksum using sha256
find . -type f -exec sha256sum {} \; | sort -k2 > checksums_$(date +%F).txt
# Compare to known-good manifest
sha256sum -c manifest.sha256
7) Audit of admin users and access controls
Check admin accounts and roles. Remove unused admin users and ensure multifactor authentication (MFA) is enabled for all admin logins.
# List admin users in DB
SELECT user_id, username, email, created, modified FROM admin_user;
# Disable an admin user in the DB (emergency)
UPDATE admin_user SET is_active=0 WHERE username='dangerous_user';
Prefer enabling Two-Factor Authentication (2FA) for admin users. Magento has a built-in 2FA module; ensure it’s enabled and enforced for admin roles.
8) Check cron jobs and background tasks
Malicious cron entries let attackers persist. Review crontab entries for the Magento user and system crontabs.
# List crons for the magento user
crontab -u magento_user -l
# Example Magento cron entries to expect
* * * * * /usr/bin/php /path/to/bin/magento cron:run | grep -v "Ran jobs by schedule" > /dev/null
If you find odd or unfamiliar cron jobs, move the server to maintenance and investigate.
9) Scan for application-level vulnerabilities
Automated scanners can find common web vulnerabilities. Run OWASP ZAP or similar tools against staging first.
- Scan login and form endpoints for XSS and CSRF weaknesses.
- Test shopping flow for injection points.
- Run authenticated scans for admin panels to see privilege escalation paths.
Keep in mind: automated tools can return false positives. Review findings manually.
10) Post-audit action plan & preventive maintenance
After the audit, put together a short runbook that includes:
- Immediate fixes applied and who applied them
- Backups taken and their locations
- Items requiring staged testing or vendor support
- A schedule for follow-up checks
10.1 Example runbook template
Runbook: Magento 2 Security Audit - 2025-XX-XX
- Executor: Alice (Ops)
- Backup: /backup/magento_db_2025-XX-XX.sql (verified)
- Issues found:
1) Outdated third-party payment module Vendor_Pay (v1.2.0) -> disabled / scheduled replacement
2) File perms: app/etc writable by web group -> corrected
3) Missing HSTS -> enabled in nginx.conf
- Follow-ups:
- Schedule composer update on staging: 2025-XX-XX
- Enable WAF ruleset: 2025-XX-XX
10.2 Maintenance schedule (suggested)
- Weekly: review logs for spikes and repeated failures
- Monthly: run composer audit, check for Magento security patches
- Quarterly: full vulnerability scan and penetration test on staging
- Annually: review access controls and update internal documentation
10.3 Emergency playbook
Have a short emergency playbook for when you suspect compromise. It should include steps to:
- Isolate the server (remove from load balancer)
- Take forensic copies of disk and DB
- Rotate application secrets and admin passwords
- Restore from last known-good backup and patch the vector
11) Example: end-to-end mini audit you can run in 45 minutes
Here’s a condensed checklist you can run quickly to get a baseline. It’s not exhaustive but will highlight major issues.
- Backup and enable maintenance mode (3 minutes)
- Check Magento and PHP versions (2 minutes):
bin/magento --version; php -v - Verify composer audit (5 minutes):
composer audit - Check file ownership & permissions (5 minutes): run the find commands from above
- Check admin users (5 minutes): query admin_user table
- Review web server TLS and headers (10 minutes): check
openssland Nginx config - Scan for obvious XSS/SQL patterns in code (10 minutes): run grep commands
Document what you find and schedule a follow-up for anything that needs a careful fix.
12) Practical tips and common pitfalls
- Don’t edit code in production. Use CI/CD so that changes are auditable.
- Use environment-specific credentials, not the same keys across environments.
- Disable developer mode and verbose error messages in production.
- Keep a minimal list of admin users and enforce strong passwords + 2FA.
- Monitor file-size changes: sudden growth in a PHP file often indicates a web shell.
13) Useful commands summary
# Magento version
bin/magento --version
# List enabled modules
bin/magento module:status
# Composer audit
composer audit
# Backup DB
mysqldump -u user -p dbname > /backup/db.sql
# Check permissions
find . -type f -exec chmod 644 {} \;
find . -type d -exec chmod 755 {} \;
# Scan for risky code
grep -R "eval\(|base64_decode|shell_exec|passthru|system\(" app/code vendor || true
# Tail Magento logs
tail -f var/log/system.log var/log/exception.log
Wrap up
Security is ongoing. This audit checklist gives you a structured way to assess and harden a Magento 2 store. If you run through the steps above, you’ll catch most common misconfigurations and risky third-party code. For Magefine customers specifically: pair this audit habit with a reliable hosting environment that provides regular backups, patching assistance, and a hardened stack optimized for Magento. That combo buys you time to focus on running the store while keeping risk low.
If you want, I can generate a tight printable checklist (one-page PDF style) based on the items above or create a templated runbook you can clone and reuse for subsequent audits. Tell me which format you prefer.




