Threat Intelligence

Honeypot Observations on PHP Vulnerabilities CVE-2026-109618 and CVE-2026-109619 (php2shell)

On 21 October 2026, the PHP project disclosed two critical vulnerabilities in PHP core, dubbed “php2shell”. We went through a week of our honeypot data to see who came knocking. The short answer: many checkers, some fuzzing, and a single source sending exploit-like payloads, which arrived 45 minutes after the advisories.

Key Takeaways

  • Before disclosure, only probes. In the eight hours before the advisories, our sensors saw parser fuzzing, a self-labelled php2shell audit and tests for the upload-progress field. None of these requests carried an exploit-like payload.
  • One exploitation source, after disclosure. A single address sent crafted serialized PHP payloads between 14:18 and 15:51 UTC on 21 October.
  • Checkers outnumber attackers. By midnight, at least ten different php2shell-themed User-Agents had probed our sensors. Most sent nothing more than a GET request.
  • Unusual is not the same as php2shell. Chunked and length-less multipart requests looked suspicious, but almost all of them came from generic scanners that had sent them long before disclosure.

Background

CVE-2026-109618 (“RCE via OOM corruption”) and CVE-2026-109619 (“RCE via stale global state”) are both rated critical (CVSS v4.0 9.2) and allow unauthenticated remote code execution. Both sit in the request handling of PHP core, including multipart parsing and session upload progress. For details, see the PHP announcement and the advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp.

The advisories went live on 21 October at 13:34 UTC. Amazon reported a first exploitation attempt against its honeypots on 17 October, and public proofs of concept from about 02:00 UTC on 21 October.

Timeline

All times are UTC. Before 21 October, we saw nothing php2shell-specific.

Time (21 Oct) Source Observation
05:25 64.176.35[.]212 Parser-limit fuzzing begins
07:41 20.243.201[.]81 First “php2shell” string in our data, from a self-labelled audit
08:43 185.182.195[.]133 Upload-progress detection test
10:10 185.4.112[.]42 Upload-progress probe
13:34 – Advisories published
14:18 45.198.224[.]169 Exploit-like serialized payloads, until 15:51
15:34 various Wave of self-labelled php2shell checkers begins
17:56 64.176.35[.]212 Second fuzzing phase, until 23:50
23:24 45.198.224[.]110 Chunked multipart checker with deeply nested field names

What We Observed

Before disclosure: fuzzing and tests

Five sources showed up in the eight hours before the advisories. None of them sent an exploit-like payload.

Source What it sent Assessment
64.176.35[.]212 (Vultr, JP) Tens of thousands of requests, many of them stressing PHP’s request parser Unclear
20.243.201[.]81 (Azure, JP) Requests for phpinfo-style paths with a “php2shell” scan ID Checker
185.182.195[.]133 The upload-progress field, posted to two “trap” scripts Detection test
185.4.112[.]42 The upload-progress field in tiny multipart POSTs Checker
85.11.167[.]243 41 bare requests for /index.php Unclear

Parser fuzzing

The busiest source, 64.176.35[.]212, spent the morning pushing PHP’s request parser to its limits, and came back for a second round in the evening. Its traffic fits the memory-pressure precondition of CVE-2026-109618. It never named itself and never sent an upload-progress field, so we cannot tell whether a researcher or an attacker was behind it.

Technique Range observed (both rounds)
urlencoded bodies 50–450 KB, up to 10,000 fields
Nested array brackets in the query string 32–39 levels (?a[b][b][b]…)
Multipart bodies up to 329 KB, one with 100,000 raw NUL bytes
Content-Length header 264−1 and 263

A self-labelled audit

The first “php2shell” string in our data arrived at 07:41 UTC, in a request header:

User-Agent: Company-PHP-Audit/0.1.0
X-Company-Scan-Id: php2shell-full-20261021_163651_JST-…
X-PHP-Audit-Stage: …

The timestamp in the scan ID converts to 07:36:51 UTC, a few minutes before the first request reached us. A second run followed at 19:22 UTC with version 0.5.0.

Tests for the upload-progress field

Two sources sent the PHP_SESSION_UPLOAD_PROGRESS field in tiny POST bodies of 29 to 296 bytes. One posted it to scripts named /trap-encoded.php and /trap-literal.php, with the User-Agent trap-test-rev2. This looks like someone testing their detection rules against an encoded and a literal field name. The other used plain curl. Before disclosure, the field reached our sensors only in tests like these.

Unclear: minimal GET requests

85.11.167[.]243, otherwise busy with IoT and NVR exploits, requested the PHP index page 41 times within ten minutes. The requests carried nothing but a Connection header and the literal User-Agent None. The exploitation source described below used the same style later that day. The style is common, though: another address had been sending identical requests daily since 15 October.

After disclosure: one exploitation source

45.198.224[.]169 had been scanning our sensors since 16 October, but only generically, including probes against DVR ports. About 45 minutes after the advisories, it switched to crafted POST requests against three PHP entry points. Every request carried a single form parameter named cook:

  Probes Payloads
Requests 72 8
Content-Length 13 28,296
Value of cook short serialized PHP scalar serialized PHP array (a:41:{…) with the class name CachedData and long runs of raw NUL bytes

All requests share the same minimal client fingerprint. The paths were /index.php, / and /remote_app.php (Host header omitted):

POST /index.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 28296
Connection: …
User-Agent: None

cook=a:41:{…

We saw no multipart body, no upload-progress field and no session cookie from this source. Our data does not show whether these payloads target either of the two CVEs.

After disclosure: a wave of checkers

From 15:34 UTC, scanners that named themselves after php2shell arrived in quick succession. Most sent a single GET request and moved on.

Time Source User-Agent Note
15:34 91.90.123[.]25 php2shell-verify/1.0 Mullvad VPN exit
17:32 143.198.209[.]212 php2shell/2.0 (patch-state check) small multipart POST
18:12 94.154.43[.]222 php2shell-scan/1.0 also unrelated PHP exploits
18:30 185.218.86[.]14 Mozilla/5.0 (X11; Linux x86_64) php2shell-detect/1.0  
19:17 91.90.123[.]5 php2shell-scan/2.0, php2shell-scan/3.1 (authorized-security-assessment) same VPN range
20:05 36.70.239[.]195 Mozilla/5.0 php2shell-checker/1.0, php2shell-check/1.0  
22:00 217.60.242[.]58 shellflow-php2shell/1.0  
23:24 45.198.224[.]110 php2shell-behavioral-check/2.0, php-cve-version-check/1.0 see below

The odd one out

The last checker of the day, 45.198.224[.]110, did more than ask for phpinfo pages. It sent ten POST requests built to stress the multipart parser:

POST / HTTP/1.1
Transfer-Encoding: chunked
Content-Type: multipart/form-data; boundary=----p2sBoundary9f2b7a

There was no Content-Length header. Each 607-byte body held one form field whose name was nested 200 levels deep. The ten requests used two fixed bodies, five each; their hashes are listed below. The address sits in the same /24 as the exploitation source, but nothing else connects them: they used different User-Agents, techniques and times, and the /24 hosts 70 active sources.

Unusual is not the same as php2shell

Hunting for odd multipart requests alone mostly finds noise. Our week of data held 347 chunked multipart requests and 1,164 multipart requests without a Content-Length header. Between 97 and 99 % of them arrived before disclosure, from generic web scanners without any php2shell-specific marker.

Comparison with Amazon’s report

Only one of the six IP addresses from Amazon’s report reached our sensors: 31.223.184[.]166 made six connections to a Dionaea honeypot on 19 October, without any HTTP content. The 17 October source did not appear at all. Different sensor networks see different traffic, so this neither confirms nor contradicts earlier exploitation.

Hunting Recommendations

The traffic that reached our honeypots suggests a few signals for web server, WAF and proxy logs. Amazon recommends looking back to at least 17 October; in our data, the first related requests appeared on 21 October.

Signal What it meant in our data How to use it
urlencoded POST with raw NUL bytes and serialized PHP data (a:<n>:{, O:<n>:") in a parameter The only exploit-like payloads Strongest signal in our data
PHP_SESSION_UPLOAD_PROGRESS in a POST body Tests and probes, all before disclosure Rare in legitimate traffic: review every hit
User-Agent containing php2shell or php-cve-version-check Checkers, never an exploit payload Indicates scanning, not exploitation
Literal User-Agent None with only a Connection header The exploitation source, but also unrelated scripts Supporting signal only
Chunked multipart, multipart without Content-Length, deeply nested field names, very large form bodies Almost always generic scanners or fuzzing Supporting signal only

When rating a hit, three lessons from our data help:

  • A checker hit means a host is being scanned, not compromised. Self-labelled checkers made up most of the php2shell traffic we saw.
  • Combine weak signals. Odd multipart requests alone are mostly noise. Together with an upload-progress field or a php2shell User-Agent, they deserve a closer look.
  • Treat IP matches as leads, not proof. Several sources above are VPN exits or cloud hosts shared by many users.

An exploit-like request shows an attempt, not its outcome. Our honeypots cannot tell whether a payload would have worked, so check the targeted host for the same time window.

Limitations

  • No success signal: our honeypots answer generically. They show what was sent, not whether it would have worked against a real PHP installation.
  • Incomplete bodies: some sensors truncate request bodies, drop multipart part headers or store headers only. A missing marker does not prove that it was not sent.

Indicators

The roles reflect what our sensors captured. Several addresses are VPN exits or cloud hosts and may be shared.

IP address Role Relevant activity on 21 Oct (UTC)
45.198.224[.]169 exploitation attempts 14:18–15:51
64.176.35[.]212 unclear: parser fuzzing 05:25–23:58
85.11.167[.]243 unclear: minimal GET requests 08:36–08:46
20.243.201[.]81 checker 07:41–19:22
185.182.195[.]133 detection test 08:43
185.4.112[.]42 checker 10:10–10:11
91.90.123[.]25 checker 15:34–20:58
143.198.209[.]212 checker 17:32
94.154.43[.]222 checker 18:12–18:17
185.218.86[.]14 checker 18:30
91.90.123[.]5 checker 19:17–19:50
36.70.239[.]195 checker 20:05–22:19
217.60.242[.]58 checker 22:00–22:46
45.198.224[.]110 checker 23:24–23:56
Request marker Source
Parameter cook= with serialized CachedData payload, User-Agent None 45.198.224[.]169
Boundary ----p2sBoundary9f2b7a, chunked, no Content-Length 45.198.224[.]110
Boundary ----php2shell followed by 12 hex characters 143.198.209[.]212
Boundary ----artexboundary78 64.176.35[.]212
Header X-Company-Scan-Id: php2shell-full-* 20.243.201[.]81

Run Your Own Honeypots

The honeypots that captured this activity, such as Tanner, H0neytr4p and Dionaea, are all part of T-Pot, our open-source multi-honeypot platform. T-Pot bundles more than 20 honeypots with the Elastic Stack for analysis and visualization, and installs on a single host. If you want to see for yourself what hits the internet after the next big disclosure, give it a try.