← Verdict cards Cutsign
Patch now + hunt Exploited in the wild CISA KEV · federal due Oct 29 Mass probing underway EOL lines: source-only backports as of 2026-10-28

PHP2Shell emergency release

Two unauthenticated RCE flaws in the PHP engine — CVE-2026-109618 / CVE-2026-109619, CVSS 4.0 9.2 — leaked ahead of coordinated disclosure, patched in an emergency release October 21. Cloudflare has observed millions of exploitation attempts, some delivering the Mirai-derived Potassium botnet; watchTowr has observed in-the-wild exploitation of both CVEs. As of Oct 26 exploitation is confirmed working, not just scanning: researchers took over an Apache mod_php honeypot, a European government entity was compromised with agentic-AI post-exploitation, and Mirai operators plus ASLR-bypass exploits have joined. CISA listed both CVEs in KEV on Oct 26 (federal remediation due Oct 29, forensic-triage flag set); on Oct 27 industrial vendors — Siemens, Schneider Electric, ABB, Johnson Controls, Belden, HMS, Wibu-Systems — confirmed PHP-based OT/ICS products affected, Belden NetModule NRSW without a patch.

Verdict: patch outside the normal cycle, and hunt while you patch. Unauthenticated RCE in the engine that runs most of the web, with exploitation observed in the wild and mass probing underway — this does not wait for the monthly window. Successful compromises are now confirmed (Oct 24–26) — treat unpatched internet-facing PHP as presumed targeted, and hunt back to Oct 20 when the details leaked. PHP 7.4 / 8.0 / 8.1 get no binary release — official source-backport branches and distro packages are the only routes, and migration is the real fix. The PHP team published official interim mitigations (below) for installations that cannot patch today. Hunting behaviors are published and concrete, which makes this one of the rare patch events that is also immediately huntable.

30-second read

Both flaws are use-after-frees in PHP core (session upload-progress handling and fatal-error paths), reachable without authentication. Observed exploitation recycles PHP workers, leaks memory through PHPSESSID cookies, and abuses session upload-progress handling to run shell commands; the observed exploit targets Apache mod_php, and exploitation is easier where session upload-progress is enabled. Some attempts fetch a Potassium loader from 92.118.112[.]100.

Fixed versions — October 21, 2026

LineUpgrade toNote
8.58.5.12supported lines, all fixed in the emergency release
8.48.4.27
8.38.3.36
8.28.2.35
8.1 / 8.0 / 7.4no binary releaseEOL — official minimal source-backport branches exist on github.com/php/php-src (PHP-7.4-CVE-2026-109618-109619 etc.) for build-from-source; otherwise distro/vendor backports (e.g. Plesk shipped one). Affected code reaches back to PHP 5.4
8.2 itself reaches EOL December 31, 2026 — patching to 8.2.35 buys ten weeks, not a destination. Linux distros and LTS vendors received patches in advance; check vendor packages.

Official mitigations (php.net) — if you cannot patch today

From the PHP team's advisory: these reduce exposure to the confirmed paths but "do not make an installation safe" — patching is the fix.


# CVE-2026-109619 (stale global state) — blocks the confirmed session path:
session.upload_progress.enabled=0     ; php.ini / FPM pool / server config,
                                      ; NOT ini_set() or .user.ini — then restart every worker
fatal_error_backtraces=0              ; PHP 8.5 only, blocks the fatal-backtrace path

# CVE-2026-109618 (OOM corruption) — starve the allocation-failure primitive:

memory_limit=-1                       ; via php_admin_value so apps cannot override
post_max_size = 8M                    ; (32M if uploads needed); upload_max_filesize below it

# plus web-server/proxy limits on decoded size, field/part/header counts, nesting —
# enforced even without a usable Content-Length
# availability boundary: container/cgroup limit killing only the worker.
# Do NOT use RLIMIT_AS / RLIMIT_DATA — they can trigger the vulnerable allocation failure.

Exposed if

  • Internet-facing PHP below the fixed versions — the probing is indiscriminate
  • PHP 7.4 / 8.0 / 8.1 or older anywhere, without a distro backport
  • Session upload-progress enabled and/or Apache mod_php (the observed exploit's target)

Not exposed if

  • PHP 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 or later
  • A distribution backport patch is applied (verify by changelog, not version string)

Hunt — published behaviors

Detection coverage — as of Oct 28

CategoryVendorStatus
VendorPHP projectEmergency release + mitigations — fixed versions Oct 21 14:00 UTC; official interim mitigations published (section below); minimal source-backport branches for EOL 7.4/8.0/8.1; distros and LTS vendors received patches in advance; GHSA advisories for -109618 / -109619; follow-up advisory CVE-2026-115560 issued Oct 23
VM scannersTenableFAQ published for both CVEs; plugin IDs not confirmed in public reporting — check the plugin feed for the version checks
Qualys / Rapid7Nothing published found — verify QID / InsightVM content directly
Hunting contentHuntress / watchTowr / WizPublished — Huntress process-spawn guidance (Florian Roth's process-watcher for Linux without EDR) with Sigma/YARA promised to huntresslabs/threat-intel; watchTowr reproduction + ITW reporting; Wiz behavior write-up (the hunt list above)
WAF / edgeCloudflareRules live since Oct 21 — deployed ~9 hours before public disclosure, enabled by default on all plans including Free; Oct 22 emergency release renamed seven rules to carry the CVE IDs. Paid plans: confirm the Managed Ruleset's PHP2Shell rules run in Block. Cloudflare reports attackers already mutating payloads to evade — WAF is cover, not the fix
AkamaiRule shipped — Adaptive Security Engine 3000991 v1 "PHP Remote Code Execution Attack Detected" covers both CVEs; existing command-injection rules catch weaponized payloads. Verify active and blocking on every hostname — default status not stated
Emerging ThreatsIDS signatures published for both CVEs (Suricata/Snort rule coverage thread)
ExposureCensysLive advisory with exposure search for internet-facing PHP
Vendor impactPalo AltoStatement: not aware of exploitation against PAN products
KEVCISAListed Oct 26 — both CVEs (catalog entries: "PHP Memory Corruption" / "PHP Stale Internal Request-State"); federal due date Oct 29 under BOD 26-04; forensic-triage flag: Yes (CISA expects triage of exposed hosts, not patch-and-forget); ransomware use: unknown. CISA's Oct 21 alert (revised Oct 23 and 26) adds a Sigma rule and says organizations that cannot patch, or still run PHP ≤8.1, should take PHP systems offline until patched

Do now

  • Patch internet-facing PHP first; then internal; verify EOL hosts got distro backports or are flagged for migration
  • Run the hunt list against web-server logs and EDR for the window since Oct 20 (details leaked pre-patch)
  • Inventory where session upload-progress is enabled and where mod_php still runs
  • Container images bundling PHP need rebuilds, same as any runtime flaw
  • OT/ICS: check Siemens, Schneider Electric, ABB, Johnson Controls, Belden, HMS and Wibu-Systems advisories for PHP-based products; PHP is often embedded and not visible to a version scan

Escalation triggers

  • Any hit on the hunt behaviors or campaign infrastructure → incident lane immediately
  • Confirmed successful compromises — triggered Oct 24–26 (honeypot takeover, European government entity); unpatched internet-facing PHP is now a presumed-targeted asset, not a patch-cycle item
  • CISA KEV listing — triggered Oct 26, both CVEs; federal due date Oct 29, forensic-triage flag set
  • Confirmed exploitation of a PHP-based OT/ICS product (vendor advisories now list affected products; Belden NetModule NRSW has no patch — vendor says disable its web interface)
  • Potassium botnet capability reports beyond Mirai-standard DDoS

Inferred detections — while you wait

The behaviors above are published (Wiz, Huntress) but no vendor has shipped ready-made queries. These translate the published behaviors into generic query logic — tune thresholds to your traffic.

Exploit attempt shape — multipart request then memory error, from the same source:


# web / LB logs
multipart POST (content-type contains multipart/form-data)
followed within 60s by status 500 from same src_ip
| count by src_ip over 10m → investigate bursts; mass probing will be loud

Memory-leak primitive — the PHPSESSID leak is visible in responses:


# proxy / web logs with response headers
response Set-Cookie contains PHPSESSID AND cookie length > 1KB
→ near-zero false positives; any hit is an exploitation attempt that got traction

Post-exploitation lineage — the published Huntress behavior as a query:


# EDR process lineage
parent.name IN (php-fpm, php-cgi, apache2, httpd)
child.name IN (sh, bash, curl, wget, perl, python*)
also: php-fpm "child exited on signal" bursts in syslog (worker churn)

Splunk (index=*) / Elastic ES|QL (FROM logs-*) — CIM Web / Endpoint field names for Splunk, ECS for Elastic, Sysmon names for lineage; tune to your add-on or integration:


# exploit attempt shape: multipart POST then HTTP 500 from the same source inside 60 s
index=* earliest=-30d@d ((http_method=POST http_content_type="multipart/form-data*") OR status=500)
| transaction src maxspan=60s
| search http_method=POST status=500
| stats count as pairs min(_time) as first max(_time) as last values(uri_path) as paths by src
| sort - pairs

# memory-leak primitive: oversized PHPSESSID in responses

index=* earliest=-30d@d "Set-Cookie" "PHPSESSID"
| regex _raw="PHPSESSID=[^;\s]{1024,}"
| stats count by src dest uri_path

# post-exploitation lineage (Sysmon EID 1 / EDR)

index=* earliest=-30d@d ParentImage IN ("*/php-fpm*","*/php-cgi*","*/apache2","*/httpd")
    Image IN ("*/sh","*/bash","*/dash","*/curl","*/wget","*/perl","*/python*")
| stats count values(CommandLine) as cmds min(_time) as first by host ParentImage Image

# worker churn (syslog)

index=* earliest=-30d@d "php-fpm" "child" "exited on signal"
| timechart span=10m count by host

# campaign infrastructure (Potassium loader)

index=* earliest=-30d@d (dest=92.118.112.100 OR src=92.118.112.100 OR url="*92.118.112.100*")
| stats count min(_time) as first by host src dest


// exploit attempt shape: multipart POST then HTTP 500 from the same source inside the same minute
// (ES|QL has no transaction; one-minute buckets approximate the 60 s window)
FROM logs-*
| WHERE @timestamp > NOW() - 30 days
| WHERE (http.request.method == "POST" AND http.request.mime_type LIKE "multipart/form-data*") OR http.response.status_code == 500
| EVAL minute = DATE_TRUNC(1 minute, @timestamp)
| STATS posts = COUNT(*) WHERE http.request.method == "POST", errors = COUNT(*) WHERE http.response.status_code == 500, paths = VALUES(url.path) BY source.ip, minute
| WHERE posts > 0 AND errors > 0
| STATS pairs = COUNT(*), first = MIN(minute), last = MAX(minute), paths = VALUES(paths) BY source.ip
| SORT pairs DESC

// memory-leak primitive: oversized PHPSESSID in responses

FROM logs-*
| WHERE @timestamp > NOW() - 30 days AND message LIKE "*Set-Cookie*PHPSESSID*"
| WHERE message RLIKE ".*PHPSESSID=[^;\\s]{1024,}.*"
| STATS count = COUNT(*) BY source.ip, destination.ip, url.path

// post-exploitation lineage (endpoint process events)

FROM logs-*
| WHERE @timestamp > NOW() - 30 days
| WHERE (process.parent.name LIKE "php-fpm*" OR process.parent.name LIKE "php-cgi*" OR process.parent.name IN ("apache2", "httpd"))
    AND (process.name IN ("sh", "bash", "dash", "curl", "wget", "perl") OR process.name LIKE "python*")
| STATS count = COUNT(*), cmds = VALUES(process.command_line), first = MIN(@timestamp) BY host.name, process.parent.name, process.name

// worker churn (syslog)

FROM logs-*
| WHERE @timestamp > NOW() - 30 days AND message LIKE "*php-fpm*child*exited on signal*"
| STATS count = COUNT(*) BY host.name, t = BUCKET(@timestamp, 10 minute)
| SORT t

// campaign infrastructure (Potassium loader)

FROM logs-*
| WHERE @timestamp > NOW() - 30 days
| WHERE destination.ip == "92.118.112.100" OR source.ip == "92.118.112.100" OR url.full LIKE "*92.118.112.100*"
| STATS count = COUNT(*), first = MIN(@timestamp) BY host.name, source.ip, destination.ip

Timeline

Sources

PHP — official announcement · GHSA — CVE-2026-109618 · GHSA — CVE-2026-109619 · Huntress — PHP2Shell · watchTowr — exploitation · The Hacker News — mass attempts, Oct 23 · Wiz — behaviors · Tenable FAQ · Censys live advisory · CISA KEV catalog — both CVEs, added Oct 26 · CISA alert — revised Oct 26, Sigma rule · SecurityWeek — OT/ICS vendor advisories, Oct 27

Public OSINT only — contains no internal data Marcus Liberto · source Lane and triggers per CIRT triage-flow draft Tracked story: Cutsign 10-21 → 10-22 → 10-23 → 10-26 → 10-27 (KEV, OT/ICS vendors)