Back to blog
By the Lesscode team

PHP2Shell Explained: What Happened in the PHP Attacks

Reporting checked on 25 October 2026. This account separates published research, observed attack attempts and confirmed incident reports.

The alarming part of the latest PHP security news is where the failure happened. A website could have current application code and still be exposed through the software interpreting it. In some demonstrated deployments, the dangerous work happened before the application had even started handling the request.

The name PHP2Shell refers to two critical PHP vulnerabilities disclosed on 21 October 2026: CVE-2026-109618 and CVE-2026-109619. They can permit unauthenticated remote code execution—running attacker-controlled code without first signing in. PHP issued security updates that day. A related, narrower issue received a follow-up advisory on 23 October. PHP’s official advisories are the starting point for checking the current position.

Calling this a “PHP malware outbreak” misses an important distinction. A vulnerability is a weakness. An exploit uses that weakness. Malware is malicious software that an attacker might execute or install afterward. Finding a vulnerable PHP version establishes exposure; it does not establish that the website has already been compromised.

There was also a separate WordPress ecosystem breach that involved actual malicious plugins. We return to that below, because mixing the two events produces the wrong recovery advice.

The timeline extends beyond patch day

The discovery was not an overnight event. In Calif’s original research account, Ryan Austin dates the first report to PHP to 11 August, a working demonstration shared with PHP to 14 August, and confirmation from PHP to 15 August. Further findings followed. Those dates describe the researchers’ disclosure process, rather than the beginning of criminal activity.

17 October: an attack attempt predating disclosure. Amazon Threat Intelligence later identified a PHP2Shell attempt in its MadPot honeypot telemetry from this date. The source used commercial anonymization infrastructure. AWS said it did not know how the actor obtained exploit information during the embargo. That evidence does not justify naming a leaker or claiming an insider breach.

20 October: advance warning. PHP announced that critical fixes were scheduled for 21 October at 14:00 UTC, giving operators a chance to prepare.

21 October: fixes, demonstrations and broader attempts. AWS reported further attempts before the scheduled disclosure time, followed by additional public proof-of-concept activity after release. Its analysis explicitly left open whether the observed early attempts would have succeeded against real-world systems. See the AWS investigation.

23 October: a narrower follow-up. PHP published additional guidance about session upload progress. A response plan based solely on the first day’s headlines could therefore be incomplete.

The practical significance of the chronology is straightforward: an investigation should not automatically begin on patch day. A date on a public advisory is a disclosure milestone, not proof that attacks began then.

Inside the PHP vulnerability: a request ends, but its state is unsafe

PHP processes incoming web requests using native engine code as well as application scripts. It allocates memory for request data, tracks internal objects and eventually releases that memory. Persistent workers may then process another request.

The two advisories describe different failures around that lifecycle.

CVE-2026-109618: cleanup trusts unfinished data

PHP’s out-of-memory advisory describes an abrupt exit when memory allocation fails. Some internal data can become visible to cleanup code before initialization is complete. If execution stops at that point, shutdown can operate on data that was never made valid.

Think of a record marked “ready” before all its fields have been filled. An interruption leaves the marker in place, and a later step trusts it. In PHP, the consequences are native memory corruption, rather than simply a missing form value.

The advisory validates remote code execution against Apache mod_php, including a path before application code executes. Successful execution has the privileges of the web worker account; it does not automatically mean root access. Reliability depends on the build, extensions, frontend and memory layout. This is more specific than the claim that any request can instantly take over every PHP server.

CVE-2026-109619: one request leaves a dangerous reference for the next

The stale-state advisory describes internal state that still points to request memory after that memory has been freed. Another request handled by the same worker can encounter the old reference before normal initialization clears it.

Here the problem crosses a request boundary. One operation leaves the stale state; a later operation consumes it. The documented consumers include session upload progress and certain early configuration diagnostics. Some routes depend on application behavior or configuration. PHP-FPM is not a blanket escape from the second issue: a validated route involves a suitable application operation after startup and a subsequent request reaching the same worker.

The distinction matters operationally. A mitigation aimed at one route should not be presented as eliminating every route in both vulnerabilities.

What researchers proved—and what that does not prove

Wiz’s 21 October research describes remote-code-execution demonstrations against WordPress, Drupal and Joomla deployments. The vulnerable component was PHP itself, rather than necessarily a bug in those applications. Wiz separately demonstrated disclosure of sensitive PHP process memory, including credentials and tokens, without first achieving code execution.

Those are demonstrations by the named researchers. They are not tests performed by Lesscode, and they are not a count of compromised customer websites.

Likewise, a blocked request, a public exploit demonstration and an installed backdoor are different pieces of evidence. They answer different questions: was a system targeted, was an exploitation technique viable, and did an attacker establish access? Reporting them as interchangeable makes an incident look more certain than the evidence allows.

The sources reviewed for this article do not establish a reliable global total of successful PHP2Shell compromises. AWS’s honeypot observations establish attempts; they do not establish that every payload worked on production servers. The identity of the early actor and the source of its pre-disclosure knowledge remain unresolved in that report.

The 23 October update changes the “we patched” conversation

PHP’s follow-up covers CVE-2026-115560, an unusual combination of session settings and application behavior. It involves session upload progress remaining enabled while a configured php_binary or php_serialize session handler is switched to php at runtime before session_start().

PHP recommends session.upload_progress.enabled=0 until the next regular bugfix release; applications that never change the handler at runtime can keep the feature enabled. This is a narrow condition, not evidence that every updated installation remains equally exploitable. Read the 23 October informational advisory alongside the original fixes.

Cloudflare’s updated guidance says its existing protection covers known attempts against this related issue when the default upload-progress field name is used. A customized field name falls outside that rule’s coverage. Cloudflare also reports attackers changing payloads and emphasizes patching even when WAF protections are present.

A firewall rule can reduce exposure to traffic it recognizes. It does not replace an update, prove an origin was never reached, or remove code an attacker already installed.

A different incident: stolen keys and malicious WordPress plugins

TeamUpdraft’s report describes another route into websites. The company identified unauthorized access to teamupdraft.com over 17–18 October. In its incident disclosure, updated through 23 October, it says the attacker used a compromised key and abused connections to customer sites to create accounts and install malicious plugins. The extent remained unknown in that account.

The company says its customer database was believed accessed, including service connection keys. It also says the UpdraftPlus plugin itself and its downloads were not compromised. These statements describe a management-service and credential incident, not proof that PHP2Shell was the entry point.

UpdraftPlus releases 1.26.13 and 2.26.13 revoked old UpdraftCentral connection keys. The vendor still asks affected users to inspect their sites for unexpected accounts, plugins and activity. Its current product-specific instructions should guide recovery.

Patching PHP addresses a runtime weakness. Revoking a stolen management key addresses an access route. Neither action, by itself, proves a previously installed backdoor has been removed. A site could need more than one response if more than one exposure applied.

What an affected business needs to establish now

The initial upstream fixes were PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Older branches require particular care: vendor backports may exist, but they must be verified with the provider. Check the latest supported vendor package and the follow-up advice, rather than treating this article’s version list as a permanent endpoint.

The UK NCSC’s guidance calls for finding PHP across the estate, prioritizing exposed systems, applying updates and examining possible compromise where immediate remediation was not possible. It also recommends considering taking a system offline when effective mitigation cannot be applied promptly.

For a founder or product owner, ask the operating team for evidence tied to each environment: which PHP build serves requests, when the update was deployed, whether running workers were replaced, and whether staging, containers or bundled applications were included. A current WordPress dashboard is not evidence that the underlying PHP runtime changed.

If suspicious activity is found, preserve relevant logs and involve the incident-response owner before treating the matter as a routine update. Review unexpected files, accounts, processes and outbound connections in context. A single suspicious address is not a verdict: AWS notes that its listed addresses include shared anonymization infrastructure.

The unanswered question after an emergency update is often ownership. Who is responsible for the runtime, who verifies the deployment, and who investigates the period before it? Those responsibilities remain whether a business buys a platform or commissions an application—a distinction also explored in our startup software decision guide.

For this incident, a useful completion statement needs two separate answers: the vulnerable software has been remediated, and the available evidence about prior compromise has been reviewed. “We updated the website” is too vague to establish either one.

Keep reading

Related articles.

New business / 2026

Have a process that should work better?

Bring us the bottleneck, the brittle build, or the idea. We'll give you a direct read on what to do next.