Detection & response
Was I hit?
No single rule catches every variant, and the vulnerable code runs below your application, so app logs may show nothing. Use these signals to prioritise — not to clear a system.
Last reviewed 2026-10-22
Absence of signals is not proof of safety
The memory-disclosure path can steal secrets without ever executing code on the server. Patch regardless of what you find.
Signals worth investigating
| Signal | Why it matters | Where to look |
|---|---|---|
| Memory-limit fatals right after multipart POSTs | Both CVEs are reached by pushing PHP into an out-of-memory error while it parses a request. | PHP / FPM error log + web access log |
| Bursts of HTTP 500 from one client | Exploits need several attempts to adapt to the target’s memory layout. | Access log |
| Workers dying on SIGSEGV / SIGABRT, or unusual worker churn | Use-after-free attempts that miss tend to crash the worker. | FPM log, Apache error log, dmesg / journal |
| Unusually long or percent-encoded PHPSESSID in responses | The memory-disclosure path URL-encodes leaked heap memory into the session cookie — even on sites that never call session_start(). | Reverse proxy / CDN / WAF logs of Set-Cookie (not in default access logs) |
| New .php files in the web root, unexpected child processes of the PHP user | Classic post-exploitation: web shells, curl/wget, reverse shells from www-data. | File system, EDR, process accounting |
A normal PHPSESSID is short and alphanumeric (by default 32 characters). Hundreds of characters or %xx byte sequences in one is not normal.
Search your logs
Paths are Debian/Ubuntu defaults. Adjust for your system; cover the period since early October 2026 at least.
# 1. Memory-limit fatals (PHP's exact message)
sudo grep -rh "Allowed memory size of" /var/log/php*-fpm.log /var/log/apache2/ /var/log/httpd/ /var/log/nginx/ 2>/dev/null | tail -50
# 2. Workers killed by signals
sudo grep -rhE "exited on signal (6|11)|exit signal (Segmentation fault|Aborted)" \
/var/log/php*-fpm.log /var/log/apache2/ /var/log/httpd/ 2>/dev/null | tail -50
sudo journalctl --since "2026-10-01" | grep -E "php.*segfault" | tail
# 3. Clients producing many 500s on POST (combined log format)
sudo awk '$6=="\"POST" && $9==500 {print $1}' /var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null \
| sort | uniq -c | sort -rn | head -20After patching, the new hard memory limit can also end workers abruptly. A worker exit on its own is not proof of an attack — look for clusters tied to the same client or request pattern.
Look for post-exploitation
# PHP files changed in the web root since the bugs became known (adjust path/date)
sudo find /var/www -type f -name '*.php' -newermt '2026-08-01' -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort | tail -100
# Processes the web user is running right now (shells and downloaders are red flags)
ps -u www-data -o pid,ppid,lstart,cmd | grep -vE 'php-fpm|apache2|httpd'
# Established connections owned by PHP / Apache — review every remote address
sudo ss -tpn state established | grep -E 'php|apache|httpd'WAF coverage
Managed rules are a stopgap while you patch. Check your provider’s PHP2Shell guidance. Cloudflare published its rule IDs — see the Cloudflare page.
Vendor detections
If you run one of these products, their write-ups describe the signatures and hunting queries they shipped.
- AkamaiCritical RCE vulnerabilities in PHP core
- ImpervaPHP2Shell vulnerability updates
- CorelightPHP2Shell detection
- CrowdStrikeProtecting customers from PHP RCE zero-days
- Unit 42CVE-2026-109618 / CVE-2026-109619
- Cisco TalosTwo critical RCEs in PHP core
- watchTowrPHP RCE FAQ: CVE-2026-109618
- SansecPHP2Shell: critical PHP RCE
Do not run “PoC” scripts from GitHub on your servers
Several repositories claim to be PHP2Shell exploits or scanners. Tenable could not verify that any of them work; fake PoCs are a common way to deliver malware to defenders. Use vendor tooling or the checks on this page.
If you find something
- Preserve evidence first: copy logs, take a disk / memory snapshot if you can, before you rebuild.
- Patch or isolate the host. Prefer rebuilding from a clean image over cleaning in place.
- Rotate everything PHP could see in memory: database passwords, API keys, OAuth client secrets, SMTP credentials, app keys (
APP_KEY, WordPress salts), TLS private keys if PHP had access. - Invalidate sessions so stolen cookies stop working, and ask admins to re-authenticate.
- Check the blast radius: what else those credentials reach (cloud accounts, internal APIs, other databases).