Magento 2 Security Audit
Magento 2 is one of the most targeted e-commerce platforms. Primary attack vectors: extension vulnerabilities, outdated versions without patches, exposed admin path. Adobe/Magento regularly publishes APSB bulletins — no Magento site should run without current security patches.
Checking Version and Patches
# Current version
php bin/magento --version
# Check applied patches
php ./vendor/bin/magento-patches status
# Composer audit — dependency vulnerabilities
composer audit
# Compare with latest release changelog
# https://experienceleague.adobe.com/docs/commerce-operations/release/notes/overview.html
Sites on Magento 2.3.x (EOL since September 2022) and 2.4.3 and below are critically vulnerable. Upgrade to 2.4.6+ is mandatory.
Admin URL
By default, Magento 2 uses /admin or a random suffix from app/etc/env.php:
// app/etc/env.php
'backend' => [
'frontName' => 'admin_secretpath'
],
Verify through Nginx that the admin path is not indexed and restricted by IP:
location /admin_secretpath {
allow 192.168.1.0/24;
allow 10.0.0.5;
deny all;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
include fastcgi_params;
}
If frontName contains admin, backend, adminer — change immediately.
Two-Factor Authentication
Magento 2.4.x includes 2FA out of the box (module Magento_TwoFactorAuth). Verify 2FA is enabled and not disabled via configuration:
php bin/magento config:show twofactorauth/general/enabled
# Should be: 1
# Force enable
php bin/magento config:set twofactorauth/general/enabled 1
# View providers
php bin/magento config:show twofactorauth/general/force_providers
# google, duo, authy, u2fkey
File Permissions Check
# File owner
stat /var/www/shop.com/app/etc/env.php
# Should be owned by www-data (or nginx), NOT root
# env.php permissions — read-only for owner
chmod 640 /var/www/shop.com/app/etc/env.php
chmod 640 /var/www/shop.com/app/etc/config.php
# Pub/media should not contain PHP
find /var/www/shop.com/pub/media -name "*.php" -type f
find /var/www/shop.com/pub/static -name "*.php" -type f
# Nginx: block PHP in media
location ~* /pub/media/.*\.(php|phtml|php3|php4|php5|phps)$ {
deny all;
}
Extension Verification
Third-party extensions are the most common source of vulnerabilities:
# List installed extensions
composer show --installed | grep -v magento/
# Check each extension for CVE
# Database: https://nvd.nist.gov/vuln/search?query=magento
# MageReport: https://www.magestore.com/magento-2-security
# Check extensions without updates for more than 2 years
composer show --installed | awk '{print $1, $2}' | while read pkg ver; do
composer show "$pkg" --all 2>/dev/null | grep "time"
done
Extensions that inject JavaScript directly into layout XML without CSP are potential vectors for Magecart (card skimming attacks).
Content Security Policy
# Check CSP header
curl -I https://shop.com/ | grep -i "content-security-policy"
# Enable CSP in Magento 2.3.5+
php bin/magento config:set csp/mode/storefront/report_only_mode 0
php bin/magento config:set csp/mode/admin/report_only_mode 0
// Custom CSP via WhitelistConfigInterface
class CspWhitelist implements \Magento\Csp\Api\CspWhitelistXmlInterface
{
public function getWhitelist(): array
{
return [
['id' => 'script-src', 'value' => 'https://js.stripe.com'],
['id' => 'frame-src', 'value' => 'https://js.stripe.com'],
];
}
}
Checking for Magecart Injections
Magecart attacks through embedded JS for card data theft:
# Check JS files for modifications
find /var/www/shop.com/pub/static -name "*.js" -newer /var/www/shop.com/composer.lock | \
head -20
# Check inline JS in database
mysql -u root -p magento2 -e "
SELECT value FROM core_config_data
WHERE path LIKE '%script%' OR path LIKE '%tracking%' OR path LIKE '%google%'
AND value LIKE '%<script%';"
# Check CMS blocks for malicious JS
mysql -u root -p magento2 -e "
SELECT identifier, content FROM cms_block
WHERE content LIKE '%eval(%' OR content LIKE '%document.write%'
OR content LIKE '%fromCharCode%';"
SQL Injection in Custom Modules
// Vulnerable pattern (found in older extensions)
$query = "SELECT * FROM catalog_product_entity WHERE sku = '" . $sku . "'";
$result = $this->_resource->getConnection()->query($query);
// Secure via Magento 2 ResourceModel
$connection = $this->resource->getConnection();
$select = $connection->select()
->from(['e' => 'catalog_product_entity'])
->where('e.sku = ?', $sku);
$result = $connection->fetchAll($select);
Check all custom modules for direct string concatenation in SQL queries:
grep -r "getConnection()->query" /var/www/shop.com/app/code/ | \
grep -v "//.*query" | grep "\$_GET\|\$_POST\|\$_REQUEST\|\$request->getParam"
Checking Logs for Attacks
# Suspicious admin requests
grep "POST.*admin" /var/log/nginx/access.log | \
awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# Brute force attempts
grep "401\|403" /var/log/nginx/access.log | \
awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# Magento security log
cat /var/www/shop.com/var/log/exception.log | grep -i "authentication\|unauthorized" | tail -50
Encryption Keys
# Verify crypt/key in env.php is not empty and sufficiently long
php -r "
\$env = require '/var/www/shop.com/app/etc/env.php';
\$key = \$env['crypt']['key'];
echo 'Key length: ' . strlen(\$key) . PHP_EOL;
echo 'Key entropy OK: ' . (strlen(unique_chars(\$key)) > 20 ? 'Yes' : 'No') . PHP_EOL;
"
# Key rotation (re-encrypts card data, API keys in database)
php bin/magento encryption:payment-data:update
Timeline
Magento 2 security audit with vulnerability report and recommendations — 2–3 days. Including checks of all third-party extensions, server configuration, database, and log analysis.







