
Every few months the industry runs the same play. A critical flaw turns up in something everyone depends on. Proof of concept (PoC) code appears on GitHub. Scanners and opportunists pick it up and start working through the internet. The vendor ships a fix, the advisories catch up, and the post-mortems arrive a week later to explain what the attackers understood on the first morning. The industry has been through this cycle more times than anyone can count, and each time the critical steps happen faster.
We saw the same playbook this week with PHP2Shell, but at unprecedented speed. Within 30 minutes of the first public PoC appearing, Artemis identified an actor using a weaponized copy of it, rewritten to steal credential files, against vulnerable PHP sites. This happened before the vendor had publicly confirmed exploitation and before CISA had listed either CVE. By the time the first public confirmation of exploitation appeared, that first wave was already over.
The gap between a public PoC and a live campaign has been shrinking for years, and 30 minutes is unlikely to be the floor. As open-source models continue to improve and abliterated models become more capable, that window will keep shrinking. Keeping pace means running the first hours of a response at the same speed, with agents doing the hunting and detection work instead of a ticket queue.
What we saw
Most PoCs ship with a harmless test command. The weaponized version Artemis first observed swapped it for one that reads .env from the web root and then searches the host for more. PHP applications often keep database passwords, API keys and cloud credentials in .env, so the point was to find out what else those passwords and keys would open: databases, cloud accounts, third-party services. Stealing credentials is a common first step: it gives an attacker a way in or a route to move laterally before you patch, and those credentials still work after you do.
Meeting attacker speed with agentic response
PHP pre-announced a critical release on Monday evening without saying what it fixed. A notice like that can be an actionable event on its own. It is a pre-warning that lets you start assessing your exposure agentically and building posture before a CVE number, an exploit or a patch exists. The response can start there, hours before the first exploit request rather than hours after it.
Start by answering three questions about your own environment: do we run this, can an attacker reach it, and what could they get to from it. Everything running the affected software is a long list in any sizeable estate. The short list is what an attacker can reach, what is likely to be vulnerable, and what could lead to broader access in the environment. When Artemis put these questions to its customers’ environments, we found that over half of the vulnerable PHP servers were reachable, and 1 in 3 had an end of life version that could not be updated.
Artemis builds these as attack paths, with an entry, an objective, the hops in between, and where detection coverage exists. A new publicly exploitable vulnerability adds an entry point that didn’t previously exist and can change which paths matter most.

Build generic detection before the PoC exists
You don’t need the exploit to know what a compromised PHP worker does afterwards. It starts a shell. It fetches something with curl or wget. It launches an interpreter it never normally runs. It crashes and restarts. Build detections for those behaviors on whatever telemetry you already have, before any PoC exists, and keep them generic enough to survive the next one. This week a behavioral detection written for PHP payload mutation caught the evening’s second wave before anyone had seen it.
Build specific detection once the PoC is public
A public PoC provides fingerprints and IOCs: a user-agent string, a multipart boundary, a request field that ordinary traffic to a site root never carries. Once those are public, add detections for them at the edge, on the host and on the network, with severity that depends on whether the edge blocked the request or passed it through.
Then run the new detections over the days before the disclosure, because the first attempts usually predate the first advisory.
Patch, then make sure you’d see it
When available, update to a fixed release, starting with the exposed assets at the top of your attack paths, and confirm the fix is applied. If patching isn’t practical, apply stopgaps as one layer of defense in depth and make sure you have visibility into an attempt and anything that followed it.
For PHP2Shell, update to a supported PHP release, then restart every PHP-FPM pool and Apache and rebuild container images. On end-of-life versions, disable session.upload_progress and apply PHP’s other stopgaps. If patching isn’t practical, those help mitigate the known exploit path but not the bugs, so watch for attempts and anything that follows.
Keep watching
Patching doesn’t end the response. Campaigns like this one keep evolving for days: new PoC variants, new user-agents and payload shapes, new IOC lists, new WAF rules with quirks of their own, and a second wave that looks different from the first. A day after release, the user-agent family grew by more than a dozen variants in one evening as scanners started to pick up the PoC, and a detection set written in the morning and left alone would have missed most of it.
Each change should feed back into the hunts and detections as it lands, and the loop keeps running until the activity dies down.
Keeping pace
PHP2Shell won’t be the last vulnerability to follow this pattern, and the next one will likely move faster. Keeping pace means starting from the first notice, knowing your exposure and attack paths before a PoC lands, building detections before and after it does, and keeping them current until the activity dies down.
Signals
| Signal | Source | MITRE |
|---|---|---|
Multipart POST to / carrying the upload-progress marker, scored by whether the edge blocked or passed it | WAF and CDN logs | T1190 |
| PHP worker spawns a shell, interpreter or download tool | EDR, cloud runtime | T1059 |
Web server user reads .env or writes .php outside cache paths | EDR file telemetry | T1552.001 |
| Traffic to or from the actor’s hosting block | Firewall, VPC flow logs | T1071 |
| Internet-exposed host with the CVE holding a role that reaches secrets, with no detection on the path | Cloud config, scanner, IAM | T1552.005, T1555.006 |
Indicators of Compromise
| Type | Value | Context |
|---|---|---|
| IP | 64.95.12[.]7 | Source of the first exploit wave |
| Network | 64.95.10.0/23, 64.95.12.0/23 (AS399629) | Actor hosting block, scanning more broadly since |
| User-agent | contains php2shell | PoC tooling; the same actor also used an ordinary browser user-agent |
| Multipart boundary | contains poc618 or poc619 | PoC tooling |
| IP | 47.212.110[.]207 | Scanner |
| IP | 193.32.126[.]160 | Scanner |
| IP | 167.172.179[.]6 | Scanner |
| URL path | /__php2shell_version_probe_<id>__.php | Version probe |