
PHP2Shell: NACSA Urges Immediate PHP Patching
PHP2Shell: NACSA Urges Immediate PHP Patching
On 21 October 2026 the PHP project shipped emergency releases for a pair of engine-level bugs now marketed as PHP2Shell. They allow unauthenticated remote code execution in PHP itself, not in an application built with it. Two days later, NACSA's National Cyber Coordination and Command Centre (NC4) published advisory NC4-ALR-2026-000011 telling Malaysian organisations with internet-facing PHP to patch immediately, and to isolate or take systems offline if they cannot.
The number that explains the urgency comes from Wiz: the affected code sits in a runtime that, by their estimate, powers roughly 70% of the internet. The number that should worry Malaysian teams is different: most of you do not own the PHP serving your site.
What PHP2Shell actually is
The advisory tracks CVE-2026-109618 (remote code execution via out-of-memory corruption) and CVE-2026-109619 (remote code execution via stale global state). Both are engine bugs, which changes the response. WordPress, Laravel, a hand-rolled contact form and a decade-old internal tool are equally exposed, because the flaw lives below all of them. Auditing plugins or frameworks for this is wasted effort.
The CVSS v4.0 score is 9.2, but the vector carries high attack complexity and present attack requirements. This is not a one-request worm yet. It is a memory-safety bug in the most widely deployed web runtime on earth, with public analysis and demonstrations already circulating, and Wiz calls it Heartbleed-like because the corruption path can leak process memory before code execution is reached.
The server API changes your exposure. mod_php is the worst case: the engine runs inside the Apache worker, and request shutdown is invoked even when startup failed, so a request that dies during initialisation still reaches the vulnerable teardown path. PHP-FPM exits the worker child on startup failure, which is why the confirmed full exploit was demonstrated against the embedded model. That is not a licence to skip FPM. FrankenPHP embeds PHP the same way and should be treated as exposed; LiteSpeed's LSAPI behaves more like FPM.
In Malaysia, the patch is usually your host's job
Most Malaysian SME sites sit on shared hosting where a control panel pins PHP per domain: cPanel with EasyApache 4 and MultiPHP Manager, CloudLinux's PHP Selector, Plesk, DirectAdmin. The tenant picks 7.4 or 8.1 from a dropdown. The tenant cannot rebuild the package.
If that is you, your application repository has nothing to fix. The unit of patching is the host's package set and every per-pool build the panel still offers. Ask three questions:
- What exact PHP version and SAPI serves this domain, per pool, not "the latest"?
- Has that build been updated to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, and when?
- Are old branches still selectable, and is
mod_phpstill enabled anywhere?
"We are on the latest version" is not an answer. 8.3.35 was the latest yesterday, and it is vulnerable. Ask for the string, then verify it yourself. The cPanel EmailTrack flaw in September already showed how much authority a hosting layer holds over every tenant at once: a control-panel bug is a fleet problem, and so is a runtime bug.
If your provider cannot patch on your timeline, NC4's advice is to isolate or take the service offline. On shared hosting that call belongs to the operator, so your realistic option is to move. Better to learn that this week than during an incident.
Verify the PHP that actually answers requests
php -v on the shell tells you about the CLI binary. That is rarely the thing serving traffic. On a typical Ubuntu box you can have /usr/bin/php at one version, three FPM pools at others, and an Apache module from a fourth package. Check the SAPI, not the box.
The fastest check is a temporary file that prints the web runtime:
<?php
// drop as /tmp/version.php behind your vhost, fetch it, then delete it
header('Content-Type: text/plain');
echo PHP_VERSION, ' ', PHP_SAPI, PHP_EOL;
A curl -sI https://example.my/ returning X-Powered-By: PHP/8.3.35 is a second signal, though many setups hide it. Neither replaces a host-side inventory.
For a server you own, this read-only script enumerates binaries, detects mod_php, lists FPM pools and flags pools with no memory ceiling:
#!/usr/bin/env bash
# php-sapi-audit.sh - read-only inventory of PHP runtimes and FPM pool limits
set -u
patched() { # $1 = version; 0 patched, 1 vulnerable, 2 unsupported branch
local v=$1 major minor patch
IFS=. read -r major minor patch <<<"${v%%-*}"
case "${major}.${minor:-0}" in
8.5) [ "${patch:-0}" -ge 12 ] ;;
8.4) [ "${patch:-0}" -ge 27 ] ;;
8.3) [ "${patch:-0}" -ge 36 ] ;;
8.2) [ "${patch:-0}" -ge 35 ] ;;
7.4|8.0|8.1) return 2 ;;
*) return 1 ;;
esac
}
echo "== PHP binaries =="
for bin in /usr/bin/php /usr/bin/php[0-9]*; do
[ -x "$bin" ] || continue
ver=$("$bin" -r 'echo PHP_VERSION;' 2>/dev/null) || continue
sapi=$("$bin" -r 'echo PHP_SAPI;' 2>/dev/null)
patched "$ver"
case $? in
0) verdict="patched" ;;
2) verdict="unsupported branch - backport or migrate" ;;
*) verdict="VULNERABLE - patch now" ;;
esac
printf '%-26s %-9s %-10s %s\n' "$bin" "$ver" "$sapi" "$verdict"
done
echo
echo "== Apache PHP module =="
if command -v apache2ctl >/dev/null 2>&1; then
if apache2ctl -M 2>/dev/null | grep -q 'php'; then
echo "mod_php loaded: highest-risk SAPI, patch this first"
else
echo "no mod_php module loaded"
fi
fi
echo
echo "== FPM pools =="
shopt -s nullglob
for conf in /etc/php/*/fpm/pool.d/*.conf; do
pool=$(grep -m1 '^\[' "$conf" | tr -d '[]')
limit=$(grep -E '^[[:space:]]*php_(admin_)?value\[memory_limit\]' "$conf" \
| tail -1 | sed 's/.*=//; s/^[[:space:]]*//')
[ -n "$limit" ] || limit="(inherited from php.ini)"
case "$limit" in
-1) flag=" <-- no ceiling, see below" ;;
*) flag="" ;;
esac
printf '%-14s %-46s %s%s\n' "$pool" "$conf" "$limit" "$flag"
done
Run it on the box and paste the output into the ticket when a provider insists a pool is fine while it reports 8.2.34.
The documented workaround is an availability trade
PHP's own advisory is blunt that there is no clean mitigation. The interim measure that circulated first is removing the memory ceiling in the affected pool: php_admin_value[memory_limit] = -1.
A malicious allocation normally trips memory_limit and kills the request, which is what you want during an exploit attempt. With no ceiling, the allocation goes to the operating system and the OOM killer picks a victim by its own rules: the database, the control panel, or the FPM master. Set it per pool, never globally in php.ini, and only for the hours you need to build a package.
Two related mistakes. Do not use RLIMIT_AS or RLIMIT_DATA in the pool or unit file; the advisory warns that address-space limits push allocation failures into the vulnerable path. And a container memory limit is not a substitute: the cgroup kills the container, not the request, so one hostile upload becomes a restart loop.
A WAF or reverse proxy buys time by bounding the shapes the exploit needs: cap multipart parts and headers per part, cap input variable count and nesting depth, and reject multipart bodies with no usable Content-Length. Disabling session.upload_progress.enabled removes a feature some multipart tricks lean on, at the cost of upload progress bars. None of this is a fix. It is the difference between patching at 14:00 and patching at 14:00 while something scans you.
The exploit can be quiet, so rotate secrets
Because the bug lives in the engine, your framework log may record a 500 and nothing else. Weak signals worth grepping: multipart requests with unusual part counts, out-of-memory lines in the FPM log, repeated 500s followed by worker restarts, PHPSESSID values that do not match your app's format, and new outbound connections owned by the web user.
grep -Ei 'allowed memory size|out of memory|segfault' /var/log/php*-fpm.log
If any host was internet-facing, unpatched and running mod_php between 21 October and now, rotate what that process could reach: database users, SMTP and API keys, session signing secrets, any token in an environment file. Memory disclosure can expose those without code execution, and "we saw nothing in the logs" is not evidence that nothing happened.
Assume exploit development is already underway
The release was messy. Wiz's timeline records CVE data surfacing on 20 October with an inflated CVSS 10.0, the release pulled forward in response, and a container vendor publishing fixed images hours early; a researcher posted a demonstration video by accident. The gap between "advisory published" and "working exploit in public" is now measured in hours.
Wiz credits AI-assisted analysis for finding the bug fast, naming Gemini 4 Argon and GPT-5.6 Sol and roughly a week of work. The economics are clear either way: finding memory-corruption bugs in a C codebase used to be a specialist's months-long project; it is now a sprint a resourced team can run on demand. Size your patch window for days, not quarters.
Lowyat cites Censys data putting roughly 2.6 million PHP hosts on the public internet, with about 1.5 million still advertising a version that has no fixed release. Every one is a candidate for automated scanning this week.
What I would do this week
- Inventory per SAPI, not per machine: CLI, FPM pools and
mod_phpall disagree. - Patch to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, then restart FPM and clear opcache. A patched file with a warm opcache still serves old code.
- Rebuild container images instead of pulling.
php:8.2-apacheandwordpress:latestare tags, not versions, and a cached layer keeps the vulnerable build. - On 8.2, 8.2.35 is the last release before end of life on 31 December 2026, so plan the upgrade. On 8.1 or older you are already unsupported; 7.4, 8.0 and 8.1 get only hand-built source backports.
- On RHEL, AlmaLinux or Rocky with Remi's repo, confirm packages landed; the PHP Foundation warned they would miss release day.
- If you cannot patch today, isolate the service, bound multipart limits at the proxy, and treat the host as compromised.
- Rotate secrets on any host exposed while unpatched, RCE or no RCE.
Two days in, the question is not whether PHP2Shell is exploitable. It is whether the PHP answering your domain is a version you can name, on a server you control, with a patch date you can prove.
Still mapping exposure? The Citrix NetScaler forensics write-up covers the order of operations on an exploited edge device; the cPanel EmailTrack story is the closest analogue for a hosting-layer bug.
Sources
- Lowyat.NET: NACSA Urges Local Organisations To Immediately Patch Internet-Facing PHP Systems
- National Cyber Coordination and Command Centre (NC4), NACSA: NC4-ALR-2026-000011 — Critical Vulnerabilities in PHP (PHP2Shell)
- The PHP Group: Security advisory — Critical remote code execution vulnerabilities, update now
- The PHP Foundation: PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 released
- Wiz: PHP2Shell — Critical RCE in PHP affecting 70% of the Internet
- GitHub Advisory Database: GHSA-w8hw-w9fx-j79w — PHP RCE via OOM corruption
// author
Editor & Operator
Mohd Firdaus Abu Bakar (MrDodgerX) is an enterprise geospatial systems engineer in Malaysia and the editor behind hejes.my. He runs the briefing pipeline, curates and edits every draft, verifies each factual claim against primary sources, and presses the publish button — nothing ships without his review. He writes about AI, security and Malaysia's tech scene from a builder's perspective. Professional profile and code: the links below.
// sources //
fact-check verified · 23 OCT 2026 · hejes-content-fact-check
- NACSA Urges Local Organisations To Immediately Patch Internet-Facing PHP SystemsLowyat.NET · accessed 23 OCT 2026
- NC4-ALR-2026-000011: Critical Vulnerabilities in PHP (PHP2Shell)National Cyber Coordination and Command Centre (NC4), NACSA · accessed 23 OCT 2026
- Security advisory: Critical remote code execution vulnerabilities, update nowThe PHP Group · accessed 23 OCT 2026
- PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 releasedThe PHP Foundation · accessed 23 OCT 2026
- PHP2Shell: Critical RCE in PHP affecting 70% of the InternetWiz · accessed 23 OCT 2026
- GHSA-w8hw-w9fx-j79w: PHP RCE via OOM corruptionGitHub Advisory Database · accessed 23 OCT 2026
related //

Hundreds of AI Agents Hit 440+ PaperCut Instances
GreyNoise tracked AI agents exploiting PaperCut flaws, hitting 440+ instances across 395 organizations in 48 countries. Campaign mechanics and patch guidance.

cPanel EmailTrack SQLi to Root RCE (CVE-2026-67401)
cPanel patched an EmailTrack SQL injection letting a mail account run code as root (CVE-2026-67401, CVSS 9.9). Affected builds, patch steps and open questions.

CTOS Breach: When the Credit Agency Asks You to Reset Your Password
CTOS confirmed a limited subset of consumer data was accessed; password-reset notices are now reaching account holders. Here is what it means.
// join the feed
one fresh insight per week. no spam, ever.
weekly digest. unsubscribe anytime.