In April 2026, attackers acquired 31 legitimate WordPress plugins on Flippa, let the code sit dormant for eight months, then pushed a tainted update through the official SVN commits. Up to 400,000 sites ended up with an active PHP backdoor — installed through the normal update channel, signed by the right "author," and approved by WordPress.org.
This attack is not specific to WordPress. The same pattern — buy a module, wait, push a poisoned update — works as-is on Magento. The Adobe marketplace, the Tigren / MGS / Meetanshi modules backdoored in April 2025 (500 to 1,000 stores affected, including a multinational with USD 40 billion in revenue), and the "nulled" copies downloaded from forums: the extension supply chain is today the No. 1 compromise vector for a Magento store that keeps its application core up to date.
Good news: if you have SSH access to your store, you can audit your entire extension stack in 30 minutes, from the command line. This article gives you the procedure, step by step. By the end, you will know:
- Which extensions are installed, and who publishes them
- Which ones carry signatures of known backdoors
- Whether suspicious PHP has recently been dropped into
vendor/orapp/code/ - Whether a ghost admin account has been created
- Whether JavaScript is exfiltrating your payments
Why extensions have become the No. 1 vector
Three patterns have become normalized since 2024:
- The publisher abandons the module. It stays in
composer.json, and no one maintains it anymore. The first CVE discovered is exploited for months before a maintainer reacts — or never. - The publisher sells. An independent developer transfers their module on Flippa, Acquire, or a marketplace. The new buyer gets legitimate commit access. They push a harmless update, wait (eight months for the April 2026 WordPress campaign), then inject the payload. No phishing signal, no suspicious fork: it is your publisher pushing.
- The "nulled" copy. Downloaded from
wpnull24,gpldl, Telegram forums, or a Discord channel. 90% of these copies carry at least a web shell, an SEO spam injector, or a card skimmer. Endemic among MENA agencies trying to avoid licensing fees.
All three patterns converge on the same point: your vendor/ contains code executable in production that you have not audited yourself, signed by a chain of trust you no longer control.
The 30-minute audit — step by step
Prerequisites: SSH access to the store root (typically /var/www/html), an executable bin/magento, and composer installed.
Step 1 — Inventory all extensions (3 min)
cd /var/www/html
# All modules known to Magento (active AND disabled)
bin/magento module:status
# Composer details: publisher, version, source
composer show --installed | grep -iE "^(magento|adobe|tigren|mgs|meetanshi|amasty|mageplaza|webkul|landofcoder|aheadworks|wyomind)"
# List of third-party modules physically present (excluding Adobe core)
ls -la app/code/ 2>/dev/null
ls -la vendor/ | grep -vE "^(magento|adobe|composer|symfony|laminas|psr|monolog|guzzle|phpunit|webonyx|tedivm|ramsey|graphql|zendframework)"Note every non-official vendor. That's your target list to audit.
Step 2 — Verify the authenticity of the source (5 min)
For each third-party module, check where it comes from. A "marketplace.adobe.com" module is different from a "github.com/unknown/clone" module.
# Real source of each package (repository URL)
composer show vendor/module-name | grep -E "source|dist|name"
# Compare the installed version to the latest official version
composer outdated vendor/module-name
# Check the signature of `composer.lock` — any manual change is suspicious
git log --all -p composer.lock | grep -E "tigren|mgs|meetanshi" | head -50Red flags: a dist.url pointing to an unknown domain (*.ru, *.tk, bare IP), a name that doesn't match any public package, a "1.0.0" version dated 2026 for a module officially at 4.x.
Step 3 — Scan for known IOC patterns (8 min)
PHP backdoors share a handful of signatures. Four commands cover 80% of cases.
# 1. eval + base64_decode — the classic web shell pattern
grep -rEn "eval\s*\(\s*base64_decode" vendor/ app/code/ 2>/dev/null
# 2. gzinflate + base64 — obfuscated variant
grep -rEn "gzinflate\s*\(\s*base64_decode|str_rot13\s*\(\s*base64_decode" vendor/ app/code/ 2>/dev/null
# 3. preg_replace with the /e modifier — code execution via regex (banned since PHP 7 but reappears in injected code)
grep -rEn "preg_replace\s*\(\s*['\"][^'\"]*/[a-z]*e[a-z]*['\"]" vendor/ app/code/ 2>/dev/null
# 4. Known Tigren / MGS / Meetanshi backdoors — pattern documented by Sansec (April 2025)
grep -rE "License\.php|registration\.php" vendor/ | grep -iE "tigren|mgs|meetanshi"
# 5. Superglobal variables fed to eval — "HTTP shell" pattern
grep -rEn "eval\s*\(\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" vendor/ app/code/ pub/ 2>/dev/null
# 6. assert() with user input — eval equivalent in disguise
grep -rEn "assert\s*\(\s*\\\$_(GET|POST|REQUEST)" vendor/ app/code/ pub/ 2>/dev/nullAny non-empty result must be inspected line by line. A false positive happens (rare); a true positive is a compromise.
Step 4 — Recently modified files in vendor/ (3 min)
vendor/ should only change on composer install / update. Any file modified outside that window is abnormal.
# PHP files modified in vendor/ within the last 180 days
find vendor/ -name "*.php" -mtime -180 -type f -ls | head -50
# Compare to composer.lock dates — any mtime later than the last `composer install` is suspicious
stat -c "%y %n" composer.lockIn pub/media/ and pub/static/ — which should never contain executable PHP:
find /var/www/html/pub/media/ /var/www/html/pub/static/ \
-name "*.php" -o -name "*.phtml" -o -name "*.php7" -o -name "*.phar" 2>/dev/nullAny result here is, by construction, malicious.
Step 5 — Ghost admin accounts (2 min)
# List all Magento admin users
bin/magento admin:user:unlock --help >/dev/null 2>&1 # check that the command is available
mysql -u $(grep -A1 '\[default\]' app/etc/env.php | grep -oP "(?<=username' => ')[^']+" | head -1) \
-p$(grep -oP "(?<=password' => ')[^']+" app/etc/env.php | head -1) \
-e "SELECT user_id, username, email, created, modified, is_active FROM admin_user ORDER BY created DESC;" \
$(grep -oP "(?<=dbname' => ')[^']+" app/etc/env.php | head -1)Look for: an account created outside your hiring plan, a random gmail/protonmail email, a very recent creation date, an is_active=1 for an account nobody recognizes.
Step 6 — var/log/ logs and session anomalies (4 min)
# Successful admin logins over the last 30 days
grep -rE "admin.*login.*success" var/log/ | tail -50
# Distinct IPs that accessed /admin
grep -E "/admin" /var/log/nginx/access.log* 2>/dev/null | awk '{print $1}' | sort -u
# Card-scraping attempt patterns — abnormally frequent access to checkout
grep -E "/checkout/onepage|/rest/V1/carts" /var/log/nginx/access.log* 2>/dev/null \
| awk '{print $1}' | sort | uniq -c | sort -rn | head -20An attacker preparing a skimmer scouts the checkout page to confirm their injection. A single IP with 200+ hits on /checkout/onepage within a few hours is a signal.
Step 7 — Unauthorized REST API integrations (3 min)
Attackers often create an API token to persist even if you change the admin password.
mysql -e "SELECT entity_id, name, status, created_at FROM integration ORDER BY created_at DESC;" \
$(grep -oP "(?<=dbname' => ')[^']+" app/etc/env.php | head -1)
# Active OAuth tokens
mysql -e "SELECT consumer_id, key, created_at, user_type FROM oauth_token WHERE revoked=0 ORDER BY created_at DESC LIMIT 20;" \
$(grep -oP "(?<=dbname' => ')[^']+" app/etc/env.php | head -1)Any integration you did not create is a persistent point of entry.
Step 8 — Checkout JavaScript (2 min)
The final payload of a Magecart skimmer is rarely in vendor/ — it is injected into the database via core_config_data or into a template via a compromised module.
mysql -e "SELECT path, value FROM core_config_data WHERE value LIKE '%<script%' OR value LIKE '%javascript:%';" \
$(grep -oP "(?<=dbname' => ')[^']+" app/etc/env.php | head -1)
# All third-party domains serving JS on the checkout page
curl -s https://your-store.tld/checkout | grep -oE 'src="https?://[^"]+\.js"' | sort -uAny external domain you do not recognize (legitimate analytics aside) must be identified and blocked via CSP.
If you find something
Do not reboot the server. You would lose the RAM useful for forensic analysis.
- Isolate: cut public access (outbound + inbound firewall, or maintenance page).
- Snapshot: full disk image + RAM dump if possible.
- Notify: in Tunisia, the INPDP must be informed within 72 hours if personal data has leaked (law 2004-63). In Saudi Arabia, the SDAIA requires PDPL notification within 72 hours as well (in force since 14 September 2024).
- Engage an incident response provider — not your usual Magento integrator, unless they have a dedicated forensic team.
- Rotate all secrets: MySQL, SMTP, Stripe / PayPal API keys, admin accounts, SSH keys, OAuth integrations.
- Restore from a backup prior to the compromise (check the
mtimeof your backdoors to date the event) — not yesterday's backup.
Prevention: turn this audit into a continuous pipeline
The 30-minute audit answers one question: "am I compromised today?" To stop having to ask it:
composer auditin CI — blocking. Any known CVE in your dependencies breaks the build.- Written extension policy: no installation outside the Adobe marketplace or a pre-approved publisher. No "nulled." No "I found this on GitHub."
- Sansec eComscan subscription — specialized Magento scanner, paid but it detects the obfuscated variants
grepmisses. - Code escrow for your custom modules: every commit pushed to your repo + a third party (BitBucket / GitLab.com on the client side) — the agency can't hold you hostage if the relationship sours.
- Annual extension review: a "module, publisher, last update, open CVEs, alternative" matrix. Any module unmaintained for 18 months must be replaced or removed.
- WAF with Magento rules (Sucuri, Cloudflare Pro+, or ModSecurity OWASP CRS): blocks the majority of PolyShell and SessionReaper (CVE-2025-54236) attempts before they reach PHP.
- Integrity monitoring:
tripwire,aide, or simply a cron job that compares the checksums ofvendor/andapp/code/to a baseline state and alerts on diff.
Magento extension audit by Noqta
The 30-minute audit above is designed to be runnable by your technical team. If you want the same work delivered turnkey, with a prioritized report, a remediation plan, and support for PDPL (KSA) or law 2004-63 (Tunisia) compliance, that's what we do.
The full Noqta audit includes:
- Exhaustive inventory of
composer.lock+app/code+vendor/ - Extended IOC scan (Sansec signatures, obfuscated patterns)
- Integrity check of checkout templates
- Audit of admin accounts + REST integrations + OAuth tokens
- WAF + CSP + security headers review
- High/medium/low severity report + 30 / 60 / 90 day action plan
Pricing and engagement window to be confirmed with the team depending on the size of your store.
Request a Magento extension audit
FAQ
Does the audit break anything?
No. All the commands above are read-only (grep, find, mysql -e SELECT, composer show). None of them modifies the code, configuration, or database.
Do you have to stop the store during the audit?
No. The audit runs on production under load. The find commands can consume I/O on large volumes — run during off-peak hours if the store is under strain.
What if I don't have SSH access? Ask your hosting provider for it. If they refuse, that's a red flag on the contract itself — see our file on the risks of IT providers in MENA.
Magento Open Source vs Adobe Commerce: does the method change?
No. The vendor/ + app/code/ structure is identical. Adobe Commerce adds cloud modules that are not editable, but the third-party perimeter is audited in exactly the same way.
How long between the compromise of a publisher and the exploitation? The April 2026 WordPress campaign showed 8 months of dormancy. For the Magento Tigren / MGS / Meetanshi campaign documented by Sansec, the malicious code had been waiting since 2019 and was activated in April 2025 — 6 years of dormancy. The rule: if you have never audited, you are potentially already booby-trapped.
Public sources: Sansec (Tigren/MGS/Meetanshi backdoor, April 2025; PolyShell March 2026), Blue Headline (WordPress Flippa campaign April 2026), Wordfence (La Studio Element Kit, January 2026 — 20,000 sites), Adobe APSB25-88 (CVE-2025-54236 SessionReaper), Wiz Research (database ransomware history), Foregenix (Adminer SSRF technical writeup). Regulation: INPDP Tunisia (law 2004-63), SDAIA Saudi Arabia (PDPL in force since 14 September 2024).