All Posts
Operationalized Threat Intelligence
1
min read

PHP2Shell: Catching a Quiet Exploit in the Middle of a Mass-Exploitation Wave

Published on
October 28, 2026
Table of Contents

On 17 October 2026, an Amazon honeypot logged an exploit attempt against a PHP flaw that the world had not yet heard of. Four days later, the PHP project shipped fixes for two critical bugs now known as PHP2Shell. Within hours, honeypots around the internet were drowning in exploit traffic.

PHP2Shell is a pair of unauthenticated remote code execution (RCE) flaws in the PHP interpreter itself: CVE-2026-109618 and CVE-2026-109619, both rated CVSS v4.0 9.2. Because the bugs live in the runtime rather than in any one application, they reach almost anything that serves PHP over the web.

What makes PHP2Shell unusual is not just its reach. It is how quietly a successful exploit can land. Datadog Security Labs found that a working exploit can return a normal HTTP 200 and leave the PHP worker running. CrowdStrike notes that a single memory error may be the only trace left in the logs.

That changes how defenders should hunt. In this post, we walk through what PHP2Shell is, how the exploitation wave unfolded, what attackers are trying to deliver, and why the most reliable evidence of compromise sits on the host, not in the request.

Key points

• Two critical, unauthenticated RCE flaws affect PHP back to at least 5.4.0, across mod_php, PHP-FPM, php-cgi, FrankenPHP and LiteSpeed.

• Fixed releases are PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12, published 21 October 2026. Patching is the only complete fix.

• Exploitation attempts began before disclosure and turned into a mass wave from 21 October. No confirmed victim compromise had been made public as of 23 October.

• The strongest detection signal is a PHP or web server worker starting a shell, interpreter or download tool.

Two bugs, one runtime

Both PHP2Shell flaws corrupt memory inside a long-running PHP worker. Both can be reached with a single unauthenticated HTTP request, and in both cases attacker code runs with the web worker's privileges.

CVE-2026-109618 is an out-of-memory bug. PHP runs out of memory while request data is only partly set up, and request shutdown then works on invalid memory. The confirmed exploit path is Apache mod_php with default input and memory limits: body parsing hits the memory limit before any application script runs. No complete PHP-FPM exploit has been shown for this path.

CVE-2026-109619 is a use-after-free. Global state keeps pointing at freed request memory, and a later request on the same worker reads it before initialisation. Confirmed paths include PHP 8.5 fatal error backtraces on mod_php and session upload progress on both mod_php and PHP-FPM. Session upload progress is on by default. Calif researchers demonstrated RCE on nginx with PHP-FPM through that path.

CVE

Root cause

Confirmed exploit path

CVE-2026-109618 (GHSA-w8hw-w9fx-j79w)

Out of memory during request startup; shutdown touches invalid memory

Apache mod_php, default limits, before any script runs

CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp)

Stale global state read by the next request (use-after-free)

PHP 8.5 fatal error backtraces on mod_php; session upload progress on mod_php and PHP-FPM

‍

Who is exposed

The exposure is wide. Tenable traced affected code back to at least PHP 5.4.0, and every interface that serves web requests is at risk: mod_php, PHP-FPM, php-cgi, FrankenPHP and LiteSpeed.Apache mod_php carries the highest risk because it is the only confirmed path for CVE-2026-109618, where the attack runs before any application code.

Calif confirmed unauthenticated RCE against specific versions of WordPress, Drupal, Joomla and Magento. VulnCheck reports an exploit that defeats address space layout randomisation on x86-64with display_errors off, for PHP 8.4.10 to 8.4.26.

PHP branch

Status

8.2 to 8.5

Fixed in 8.2.35, 8.3.36, 8.4.27 and 8.5.12

7.4 to 8.1

No official release; minimal source backports published

5.4 to 7.3

End of life; no fix from the PHP project

Distribution packages keep their own numbering. Ubuntu 24.04, for example, fixes both flaws in php8.3 8.3.6-0ubuntu0.24.04.13, which still reports an older upstream base version.

From private report to mass exploitation in ten weeks

The PHP project received its first private report on 11 August 2026. For two months, the bugs stayed quiet. Then, on 17 October, Amazon's MadPot honeypots caught a single exploit attempt from a commercial anonymisation network, four days before anyone outside the disclosure process should have known.

On 20 October the CVE identifiers began to circulate, and PHP published advance notice of a release. The leak pushed the fixes out a day early: on 21 October, PHP released the patched versions and advisories. That same day, CISA said it had not yet observed exploitation.

The attackers did not wait. Between 02:00 and 08:00 UTC on 21 October, Amazon saw multiple proof-of-concept exploits from varied anonymised infrastructure. ELLIO logged its first PHP2Shellrequest at 08:36 UTC, less than an hour after fixed Chainguard container images went live. Wordfence counted more than 74,000 exploit or probing attempts between 20 and 22 October.

Date (2026)

Event

22 October, 21:21 UTC

Sophos withdraws its claim of one successful exploitation; the payload was blocked and never delivered

22 October

32 UK government services go fully offline and four partially, largely as a precaution; no confirmed compromise

22 October

Emerging Threats publishes ten PHP2Shell signatures; Elastic merges fatal error and segfault rules

22 October

Arctic Wolf reports attempts to deliver the Potassium DDoS bot

21 October, 08:36 UTC

ELLIO sees its first PHP2Shell request, under an hour after fixed Chainguard images publish

21 October, 02:00–08:00 UTC

Amazon sees multiple proof-of-concept exploits from anonymised infrastructure

21 October

PHP releases fixes a day early after the CVE identifiers leak

20 October

CVE identifiers circulate; PHP gives advance notice of a release

17 October

First exploit attempt against Amazon MadPot honeypots

11 August

PHP project receives the first private report

So far, the wave has been loud but, as far as anyone has publicly confirmed, unsuccessful. Sophos withdrew its single claimed success on 22 October. Neither CVE was in CISA's Known ExploitedVulnerabilities catalogue when checked on 23 October, and no confirmed victim compromise had been made public. That is a reason to hunt carefully, not a reason to relax: a quiet success is exactly what this bug makes possible.

What the attackers are trying to deliver

The payloads seen on honeypots look like opportunistic crime, not a targeted campaign. Arctic Wolf and ELLIO reported attempts to deliver Potassium, a Mirai-derived DDoS bot, alongside PHPweb shells, a DDoS-for-hire booter and a Go remote-access agent.

The Potassium chain is a good example of how simple the follow-on can be. According to Sophos, the exploit would drop the bot at /tmp/nfs and run it as ./nfs php. A related attempt seen by Arctic Wolf echoed PHP2SHELL_CONFIRMED, changed to /tmp and fetched a setup script with wget. Neither source shows the payload actually downloaded or run.

The speed is what stands out. One attacking address seen by ELLIO moved from first probe to working exploit in 48 minutes, and had a PHP web shell installed 81 minutes after that first probe.

The attack chain

1. Scan. The attacker probes for vulnerable PHP through version banners and upload-progress handling. Visible in IDS, WAF and access logs as small probes and scanner request rates.

2. Send a crafted POST. An unauthenticated request to any PHP endpoint carries oversized field names or abusive multipart content. Visible only where request bodiesare inspected.

3. Corrupt worker memory. The worker runs out of memory during startup, or stale state carries across requests. Visible as a startup memory error or a worker crash, though the memory error may be the only trace.

4. Run commands. The worker starts a shell, interpreter, downloader or discovery command, or calls out. Visible in EDR, Sysmon for Linux or auditd, and survives a quiet exploit.

5. Persist and expand. Web shells, bots, credential theft, cron jobs, systemd units and SSH keys. Visible in file integrity monitoring and EDR file and process events.

Why PHP2Shell is hard to see

Most of the noise around PHP2Shell is attempts. The danger is the success that makes no noise at all. Several features of this bug work against defenders.

A successful exploit can look normal. Datadog saw exploit responses return HTTP 200 in about 3.1 seconds with the worker still running. A status code, a crash or a specific command name cannot be relied on.

Suppressed diagnostics hide evidence, not the bug. Settings such as error_reporting, display_errors, log_errors or PHP's @ operator do not stop the stale-state access. They only remove the log trail. A clean log is not proof of safety.

Request inspection has blind spots. Encrypted traffic must be decrypted first. AWS WAF inspects 8 KB of body on ALB and AppSync and 16 KB by default on CloudFront and API Gateway, configurable up to 64 KB. Many WAFs inspect only the first 64 KB, while observed exploit bodies reach about 10 MiB.

Payloads are mutating. Cloudflare has already seen payloads changed to evade its rules. Exact-string request rules and tool markers are a stopgap.

Version checks mislead. Banners can be missing or rewritten, and distribution builds like Ubuntu's keep an older upstream version string after fixing the flaws.

Process lineage can mislead. Behind nginx, the PHP-FPM worker, not nginx, is the parent of a spawned shell. Rules keyed only on the front-end server miss it.

How to detect PHP2Shell: start at the host

Detection has to answer three separate questions. Was a suspicious request sent? Did the PHP runtime behave abnormally? Did the server run an unexpected process or change its state? Only the third survives a quiet, successful exploit, so that is where we start.

Host process evidence: the strongest signal

The single most reliable indicator is a PHP or web server worker spawning something it should not. Look for a parent of apache2, httpd, php-fpm*, php-cgi, lsphp* or frankenphp starting sh, bash, dash or busybox, often with -c. On Windows, look for php-cgi.exe, httpd.exe or a PHP-hosting w3wp.exe starting cmd.exe or powershell.exe. Datadog's lab chain was apache2 running as www-data, then sh -c, then bash.

This alone will be noisy, because PHP's system(), exec() and mail() all run through sh -c legitimately. Baseline the exact command line per service and exclude exact parent and command-line pairs, never the parent alone. Escalate when arguments include /dev/tcp/, a download tool, /tmp, decoding or credential paths.

The same logic extends to discovery and staging. Observed payloads ran id, uname -a and hostname, then fetched a second stage with wget into /tmp. Reverse-shell patterns such as bash -i, mkfifo, nc -e or base64 -d under a web worker deserve immediate attention. So does a web server querying 8.8.8.8 or 1.1.1.1 directly, as the Potassium bot does, or looking up out-of-band testingdomains like *.oast.pro.

One trap: daemonised payloads such as ./nfs php are re-parented to PID 1. Capture ancestry at process creation, and also flag long-running processes owned by a web identity whose binary sits in /tmp, /var/tmp or /dev/shm.

Files and persistence

After execution comes staging. Watch for new .php or .phtml files under web roots, double extensions like shell.php.jpg, and names seen in these attacks such as wp2s.php, php2shell.php and axiom_*.php. Watch for credential reads of .env, wp-config.php or ~/.aws/credentials by a process descended from a web worker; Wordfence saw payloads print both .env and wp-config.php. And treat any crontab change, new authorized_keys file or user systemd unit created by a web identity as high priority.

PHP runtime and error logs

The runtime leaves a distinctive fingerprint when it fails during startup:

PHP Fatal error:  Allowed memory size of N bytes exhausted (tried to allocate N bytes) in Unknown on line 0

Unknown on line 0 means the failure happened before any script ran. PHP writes two spaces after Fatal error:, so match on the substrings Allowed memory size of and in Unknown on line 0. Datadog's lab logged a 16,777,216-byte limit and a 3,500,032-byte allocation. Alone, this is inconclusive, since large legitimate uploads on low-memory hosts raise the same error. Paired with a suspicious POST to the same server, it may be the only server-side trace of a successful exploit.

Worker crashes add context: Apache AH00052 ... Segmentation fault (11), PHP-FPM exited on signal 11 (SIGSEGV), or nginx upstream prematurely closed connection with bursts of HTTP 502. A crash usually marks a failed attempt. Check the host for process and file evidence anyway, in case a later attempt succeeded.

Request-layer signals

Where a WAF, IDS or decrypted traffic capture inspects request bodies, look for URL-encoded POSTs with a single very long field name (Corelight's notice starts at 65,536 bytes; Datadog's lab used about 3.5 MB), multipart content sent to routes that never accept uploads, and the PHP_SESSION_UPLOAD_PROGRESS field. Published signatures already cover much of this, including Emerging Threats SIDs 2072548 to 2072557, the Corelight Zeek and Suricata pack, and rules from Check Point, Sophos and Cloudflare.

Tool markers seen on honeypots are useful while they last. Request markers include multipart boundaries containing p2shell and probe paths like /php2shell-probe-<random>.php. A response marker such as PHP2SHELL_CONFIRMED or P2S_OK returned to a request that carried a request marker means an injected command ran. Treat that as a top-priority host investigation.

Correlate across layers

Single signals at the request and runtime layers are noisy. Joined across layers, they become strong.

Sequence

Join on

Window

Outcome

Suspicious request, then startup memory error or crash

Backend host and time; worker process ID

0–5 min

Exploit attempt reached the runtime

Suspicious request, then web worker shell or tool

Backend host and time

0–15 min

Potential remote code execution

Worker shell or tool, then new external connection

Host, process ancestry, connection

0–5 min

Potential command and control

Worker shell or tool, then web-root file, credential read or persistence

Host, process tree, file target

0–30 min

Post-exploitation activity

Upload-progress abuse, then same-worker anomaly

Worker process ID; session cookie

0–5 min

Probable CVE-2026-109619 attempt

Where one public address fronts many backends, correlate on the backend host, container or worker rather than the shared address. Keep attempts, vulnerable-version exposure and confirmedpost-exploitation in separate alert types so the attempt noise does not bury a real compromise.

Hunting for PHP2Shell

Hunt from at least 17 October 2026, the first known attempt. On exposed high-value systems, Sophos advises extending the review back to 1 August 2026, including successful administrative logins to affected applications. Work from the host outwards, because host evidence survives a quiet exploit.

1. Scope the estate. List every internet-facing host running PHP, including containers and bundled or self-compiled runtimes, and record its server interface. Put mod_php hosts first.

2. Hunt worker process trees. Find shells, interpreters, download tools, discovery commands and outbound or out-of-band connections descended from web and PHP workers in the hunt window.

3. Search the error logs. Look for memory-exhaustion errors ending in Unknown on line 0 and for worker crashes. Group hits by host and time, then pull the access-log entries from the same second.

4. Pivot to the requests. For each suspicious window, find the source address, URL, user agent and request size. Where WAF or IDS body data exists, check for exploit content and response markers.

5. Match the indicators. Search proxy, firewall, DNS and access logs for published indicators. A match shows targeting, not compromise.

6. Check the web root and persistence. On any host with a hit, look for new PHP files, binaries in /tmp and /dev/shm, credential access, cron jobs, systemd units, SSH keys and new accounts.

A process or file finding, or a success marker in a response, on an unpatched host is a probable compromise. Isolate the server and preserve the web server and PHP logs. An error-log or request finding with no host follow-on is an attempt: confirm the patch level and keep watching.

A word on indicators. Published IP addresses come almost entirely from honeypots and exposed attacker servers, and many belong to anonymisation and hosting networks. Amazon advises investigating them rather than blocking them. ELLIO found that one Potassium domain resolves to a decoy address belonging to California State University East Bay, so blocking it only blocks the university. Treat published addresses, user agents and tool markers as short-lived.

Recommendations

Three actions come before anything else:

1. Assess your exposure now. Run an immediate assessment to find out whether your environment, or any system in it, runs an affected PHP version. Include containers and vendor-bundled or self-compiled runtimes.

2. Notify promptly if you find anomalous activity. If you detect activity that may lead to unauthorised access, notify affected customers and partners as your contractual obligations require.

3. Share what you learn downstream. Consider helping, or sharing threat and threat-actor information with, the third parties, contractors and subcontractors in your supply chain, so awareness reaches every link in it.

Updating PHP is the only complete fix. Apply the official release or a vendor backport, then restart every PHP worker. Container images that bundle PHP must be rebuilt and redeployed, because a running container keeps the old runtime. CISA advises taking PHP systems offline if they run PHP 8.1 or older or cannot be patched.

Where patching has to wait, interim settings reduce exposure but do not make an installation safe. Each one also changes what your detections will see, so confirm them in the running web server through phpinfo, not the command-line interpreter.

Mitigation

Effect on the attack

Effect on detection

memory_limit=-1, enforced

Removes the predictable memory failure CVE-2026-109618 relies on; not complete

Startup memory-exhaustion errors stop appearing on that host

session.upload_progress.enabled=0

Blocks the confirmed upload-progress path for CVE-2026-109619

Requests carrying the field still show intent

fatal_error_backtraces=0 (PHP 8.5)

Removes the confirmed mod_php path for CVE-2026-109619

No change to request signals

file_uploads=Off or block multipart where unused

Removes the multipart entry point

WAF blocks become an attempt signal

pm.max_requests=1 on PHP-FPM

Stale state cannot pass to a second request

Worker churn rises; restart-based crash alerts get noisy

Restrict outbound traffic from web servers

Blocks second-stage downloads and command and control

Blocked egress from a web worker becomes a strong signal

Managed WAF rules

Stopgap for known payloads; attackers mutate around them

WAF logs give request telemetry without an IDS 

Avoid RLIMIT_AS and RLIMIT_DATA limits: they make memory allocation fail and trigger the vulnerable path.

Before relying on any detection, check that the telemetry behind it exists. Confirm that process events carry usable parent and child lineage for every PHP interface you run, that WAF andIDS inspection is not truncating bodies, that PHP's log_errors is on, and that access logs record request size and worker process ID. A rule against a missing field runs cleanly and returns nothing.

Conclusion

PHP2Shell is the kind of vulnerability that tests a security program's fundamentals. The attack surface is enormous, the exploit window opened before disclosure, and a successful attackmay leave little more than one line in an error log. Signature-based defences will keep catching the loud attempts. The quiet success will show up in process trees, file writes and outbound connections.

Patch first, restart every worker, and rebuild your containers. Then hunt back to at least 17 October, starting from the host, and keep watching your PHP workers for children they shouldnever have.

That's where we help. Anomali can provide accurate detections based on parsed OCSF logs to help you find PHP2Shell activity. Our current announcement on how Anomali is impacted by PHP2Shell is posted here.

The sources disagree on a few details. Some vendors label the upload-progress path CVE-2026-109618, while the PHP advisory places it under CVE-2026-109619; this post follows the advisory.CrowdStrike reports that its demonstrated URL-encoded path needs memory_limit below four times post_max_size, while PHP validated the startup path with default limits on mod_php. The situation is moving quickly, so recheck the advisories and the CISA catalogue before acting on this post.

References

• Arctic Wolf Labs (22 October 2026). PHP2Shell: Critical PHP VulnerabilitiesEnable Unauthenticated Remote Code Execution

• Austin, Zalewski and Cortes, Calif Research (n.d.). A tale of two PHP remote vulnerabilities

• CERT-EU (21 October 2026). Critical Vulnerabilities in PHP

• CISA (21 October 2026). Critical Vulnerabilities in PHP Require Immediate Patching

• Cloudflare (21 October 2026). Cloudflare deploys protections against php2shell vulnerability

• Corelight (n.d.). php2shell-detect

• Datadog Security Labs, Frichette, Spir and Salem (21 October 2026). PHP2Shell: detection, analysis,and remediation

• Elastic Security Labs, Groenewoud and Porras Blanch (21 October 2026). php2shell: Assessing Elastic detection coverage

• ELLIO Threat Research Lab (21 October 2026). PHP2Shell: what we observed and what to do

• Moses, Amazon Threat Intelligence (21 October 2026). AmazonThreat Intelligence identifies PHP2Shell exploitation prior to public disclosure

• Narang, Tenable (21 October 2026). php2shell: Frequently askedquestions

• PHP Group (21 October 2026). GHSA-w8hw-w9fx-j79w, CVE-2026-109618 and GHSA-6wmf-4rv5-p3rp, CVE-2026-109619

• Rapid7 (21 October 2026). Critical Unauthenticated RemoteCode Execution in PHP

• Serper, CrowdStrike (21 October 2026). CrowdStrike Protects Customers from Threats Delivered via PHP2Shell

• Sophos (21 October 2026). Advisory: PHP2Shell Vulnerabilities

• Sophos Counter Threat Unit (21 October 2026). Proof-of-concept exploit released for PHP vulnerabilities

• Stanescu, Ubuntu (21 October 2026). PHP critical vulnerability fixes available

• VulnCheck (21 October 2026). PHP2Shell Vulnerabilities

• Waddell, Pittenger and Olson, AWS (21 October 2026). UsingAWS WAF to apply mitigations for PHP2Shell

• Wordfence (22 October 2026). Attacks on PHP2Shell Continue, But No Known Compromises as a Result Yet

 

‍

FEATURED RESOURCES

October 28, 2026
Operationalized Threat Intelligence
Cyber Threat Intelligence

APT28 Spent 2 Months Inside a NATO Naval Shipbuilder and Left Behind a Loader Nobody Had Seen Before

Read More
October 27, 2026
Anomali Cyber Watch

Anomali Cyber Watch: MythicRatatoskr Backdoor & PHP2Shell

Threat intelligence briefing: Analyze Sandworm's MythicRatatoskr backdoor, millions of PHP2Shell exploit attempts, and BRONZE SANDCASTLE Meterpreter shells.
Read More
October 28, 2026
Operationalized Threat Intelligence

PHP2Shell: Catching a Quiet Exploit in the Middle of a Mass-Exploitation Wave

Learn how Anomali helps customers detect and respond to PHP2Shell.
Read More
Explore All