Someone left the factory gate unlocked in 2019 and the key still works today
CVE-2019-11043 is a buffer underflow in PHP-FPM's fpm_main.c that lets an unauthenticated remote attacker achieve arbitrary code execution on any nginx + PHP-FPM stack where the fastcgi_split_path_info directive uses a regex anchored with ^…$ and no try_files guard is present. By sending a URL containing an encoded newline (%0a), the attacker breaks the regex, forces PATH_INFO to empty, triggers an underflow that corrupts FCGI protocol memory, and ultimately overwrites PHP configuration values (php_value) to point auto_prepend_file at attacker-controlled content. Affected versions are PHP 7.1.x < 7.1.33, 7.2.x < 7.2.24, and 7.3.x < 7.3.11 — all of which have been end-of-life for years.
The vendor CVSS of 9.8 CRITICAL (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) is fair for environments that actually run the vulnerable configuration. The specific nginx directive requirement prevents a truly universal 'spray and pop' scenario — you need nginx, PHP-FPM, and the fastcgi_split_path_info pattern without try_files. That said, this config is extremely common in real-world nginx+PHP deployments; dozens of popular tutorials and framework docs recommended it for years. Combined with the CISA KEV listing, public Metasploit module, EPSS of 0.9947, and the fact that the patch has been available since October 2019, any remaining vulnerable instance represents a negligent exposure. The vendor severity is accurate.
4 steps from start to impact.
Identify nginx + PHP-FPM target
Server: nginx combined with .php responses narrow the target list. The attacker then fingerprints the PHP version via X-Powered-By headers or error pages.- Target exposes an HTTP/HTTPS endpoint running nginx
- PHP-FPM is the backend handler
- Many modern deployments strip
X-Powered-Byheaders, requiring blind version probing - PHP 8.x is now dominant; finding 7.1–7.3 unpatched narrows targets significantly
Confirm vulnerable fastcgi_split_path_info config
%0a (newline) in the path component to test whether fastcgi_split_path_info breaks on the newline. A 200 response or altered behavior (vs. a 404/403) confirms the vulnerable regex configuration is present. This is a non-destructive probe.- nginx config uses
fastcgi_split_path_infowith^…$regex - No
try_filesorifguard blocks the request before reaching PHP-FPM
- WAFs or CDNs that normalize or reject
%0ain URLs will block this probe - Configs using
try_files $uri =404beforefastcgi_passare immune
Trigger underflow and corrupt FCGI memory
PHP_VALUE entries in the FCGI protocol data, setting auto_prepend_file to a remote URL or php://input.- PHP-FPM worker processes share memory layout (default behavior)
- Attacker can send multiple rapid requests to the same worker
- Rate limiting on the endpoint can slow or break the brute-force
- PHP-FPM's process manager may recycle workers, resetting the corruption
%0a in the path. PHP-FPM error logs may show segfaults or unexpected PHP_VALUE overrides.Achieve remote code execution
auto_prepend_file is set to php://input, every subsequent POST request to any PHP page on the server executes the POST body as PHP code. The attacker now has arbitrary code execution as the PHP-FPM worker user (typically www-data or nginx). From here, standard post-exploitation proceeds: reverse shell, credential harvesting, lateral movement.- Step 3 succeeded in overwriting PHP_VALUE
- PHP-FPM worker has outbound connectivity or the attacker can exfiltrate inline
- Execution is as the web server user, not root — privilege escalation may be needed for full host compromise
- Network segmentation may limit lateral movement from a DMZ web server
/bin/sh spawned by php-fpm). File integrity monitoring on PHP configs.The supporting signals.
| In-the-Wild Exploitation | Confirmed. CISA KEV-listed. Active exploitation observed since late 2019. Used in opportunistic campaigns targeting exposed nginx+PHP stacks. |
|---|---|
| CISA KEV | Listed. Added to KEV catalog with remediation due date of 2022-04-15. Any federal agency should have patched years ago. |
| EPSS Score | 0.9947 (99th+ percentile) — among the highest-scoring CVEs in the EPSS model, reflecting widespread tooling and exploitation history. |
| CVSS v3.1 Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — 9.8 Critical. Network-attackable, no auth, no user interaction, full CIA impact. |
| Proof-of-Concept | Multiple public exploits. neex/phuip-fpizdam (original researcher tool), Metasploit module (exploit/multi/http/php_fpm_rce), and exploit-db #47553. |
| Affected Versions | PHP 7.1.x < 7.1.33, 7.2.x < 7.2.24, 7.3.x < 7.3.11. All three branches are now end-of-life. PHP 5.x and 8.x are not affected by this specific flaw. |
| Fixed Versions | PHP 7.1.33, 7.2.24, 7.3.11 (released 2019-10-24). Distro backports: Debian (DSA-4561), Ubuntu (USN-4166-1), RHEL/CentOS via php-fpm package updates. |
| Scanning / Exposure | Tenable plugin 130276, Qualys QID 150199, Nuclei template available. GreyNoise has observed consistent scanning for this CVE. Internet-facing nginx+PHP-FPM instances remain discoverable via Shodan (Server: nginx + PHP headers). |
| Disclosure Date | 2019-09-26 (reported to PHP bug tracker by Emil Lerner). Patch released 2019-10-24. Public exploit same week. |
| Researcher | Emil Lerner (@neaborom) — presented at ZeroNights 2019. Exploit tool: phuip-fpizdam. |
noisgate verdict.
The single most decisive factor is that this is an unauthenticated, network-reachable RCE with a public Metasploit module, confirmed active exploitation, and CISA KEV listing — the trifecta that makes downgrading indefensible. While the fastcgi_split_path_info configuration requirement provides marginal friction, this nginx pattern is common enough in real deployments that it does not meaningfully reduce the reachable population.
Why this verdict
- Unauthenticated RCE from the network — no credentials, no user interaction, no social engineering. An attacker needs only HTTP access to a vulnerable endpoint. This is the most dangerous attack class.
- KEV-listed with EPSS 0.9947 — CISA confirmed active exploitation. The EPSS score is in the 99th+ percentile. This is not theoretical; it is weaponized and deployed at scale.
- Metasploit module and multiple public exploits — the
phuip-fpizdamtool automates the entire chain. Metasploit'sexploit/multi/http/php_fpm_rcemodule lowers the skill bar to script-kiddie level. - Role multiplier: PHP-FPM+nginx stacks commonly serve as internet-facing web application tiers. In many organizations, these are the front door — hosting customer portals, APIs, e-commerce, and CMS platforms. Compromise of a web tier yields access to backend databases, application secrets, and internal network segments. While not a domain controller or hypervisor, the blast radius is tenant-to-segment scale (web server → database credentials → data exfiltration → lateral movement). In containerized or shared-hosting environments, the blast radius can extend to multi-tenant compromise. This keeps the floor at CRITICAL.
- Configuration requirement is common, not rare — the
fastcgi_split_path_infopattern with^…$regex and notry_filesis recommended in official PHP documentation, Laravel deployment guides, WordPress nginx configs, and countless Stack Overflow answers. The 'narrow config' argument does not hold.
Why not higher?
This is already CRITICAL at 9.5. The 0.3-point reduction from 9.8 reflects the genuine configuration prerequisite (fastcgi_split_path_info + no try_files) which does exclude some nginx+PHP-FPM deployments — particularly those using more modern config templates that include file-existence checks. A perfect 10.0 would imply zero prerequisites beyond network reachability.
Why not lower?
Downgrading below CRITICAL is not defensible for a KEV-listed, Metasploit-equipped, unauthenticated RCE. The configuration requirement is widespread enough that it cannot be treated as a rare edge case. The EPSS score of 0.9947 empirically confirms that real-world exploitation probability is near-certain for exposed instances. Any remaining unpatched instance is a live target.
What to do — in priority order.
- Add
try_files $uri =404;before everyfastcgi_passdirective — This is the most effective mitigation and takes minutes to deploy. It causes nginx to return 404 for non-existent paths before the request ever reaches PHP-FPM, completely neutralizing the underflow. Deploy within 3 days per noisgate mitigation SLA for CRITICAL findings. - Block encoded newlines in URI paths at WAF/reverse proxy — Configure your WAF (ModSecurity, Cloudflare, AWS WAF) to reject requests containing
%0aor%0din the URL path. This blocks the exploit's triggering mechanism. Deploy within 3 days. - Upgrade PHP to 8.x (or at minimum 7.4.33) — All affected branches (7.1, 7.2, 7.3) are end-of-life and receive no security updates. Upgrading to PHP 8.x eliminates this CVE and hundreds of others. Plan and execute within the 90-day noisgate remediation SLA.
- Restrict PHP-FPM process privileges and network access — Run PHP-FPM workers with minimal filesystem permissions and block outbound network access from web server hosts where possible. This limits post-exploitation blast radius even if the vuln is triggered.
- Disabling
PATH_INFOin PHP configuration alone — the vulnerability is in the FCGI protocol handling in fpm_main.c, not in PHP's use of PATH_INFO. The underflow occurs before PHP configuration is consulted. - IP-based access controls on the web server — this is an unauthenticated attack through legitimate HTTP traffic. Unless you can enumerate every legitimate client IP, ACLs won't help without breaking the application.
- PHP
disable_functions— by the time the attacker controlsauto_prepend_file, they can use techniques that bypassdisable_functions(e.g., FFI, mail() + LD_PRELOAD). This is not a reliable mitigation.
Crowdsourced verification payload.
Run this script on each target host running nginx + PHP-FPM. It checks the installed PHP version and inspects nginx configs for the vulnerable fastcgi_split_path_info pattern. Requires root or sudo to read nginx config files. Example: sudo bash check_cve_2019_11043.sh
#!/usr/bin/env bash
# check_cve_2019_11043.sh — Detect CVE-2019-11043 (PHP-FPM underflow RCE)
# Run on target host as root. Outputs VULNERABLE / PATCHED / UNKNOWN.
set -euo pipefail
RESULT="UNKNOWN"
VULN_PHP=0
VULN_NGINX=0
# --- Check PHP version ---
if command -v php &>/dev/null; then
PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION.".".PHP_RELEASE_VERSION;' 2>/dev/null || echo "0.0.0")
IFS='.' read -r MAJ MIN REL <<< "$PHP_VER"
echo "[*] PHP version detected: $PHP_VER"
if [[ "$MAJ" -eq 7 ]]; then
if [[ "$MIN" -eq 1 && "$REL" -lt 33 ]]; then
VULN_PHP=1
echo "[!] PHP 7.1.x < 7.1.33 — VULNERABLE version"
elif [[ "$MIN" -eq 2 && "$REL" -lt 24 ]]; then
VULN_PHP=1
echo "[!] PHP 7.2.x < 7.2.24 — VULNERABLE version"
elif [[ "$MIN" -eq 3 && "$REL" -lt 11 ]]; then
VULN_PHP=1
echo "[!] PHP 7.3.x < 7.3.11 — VULNERABLE version"
else
echo "[+] PHP version is patched or not in vulnerable range"
fi
else
echo "[+] PHP $MAJ.x is not affected (only PHP 7.1-7.3 vulnerable)"
fi
else
echo "[?] PHP not found on this host"
fi
# --- Check nginx config for vulnerable pattern ---
NGINX_CONF_DIRS=("/etc/nginx" "/usr/local/nginx/conf" "/opt/nginx/conf")
for CONFDIR in "${NGINX_CONF_DIRS[@]}"; do
if [[ -d "$CONFDIR" ]]; then
echo "[*] Scanning nginx configs in $CONFDIR ..."
# Look for fastcgi_split_path_info without nearby try_files
MATCHES=$(grep -rl 'fastcgi_split_path_info' "$CONFDIR" 2>/dev/null || true)
if [[ -n "$MATCHES" ]]; then
for F in $MATCHES; do
echo "[!] fastcgi_split_path_info found in: $F"
if ! grep -q 'try_files' "$F" 2>/dev/null; then
VULN_NGINX=1
echo "[!] No try_files guard found in $F — VULNERABLE config"
else
echo "[+] try_files guard present in $F — mitigated"
fi
done
else
echo "[+] No fastcgi_split_path_info directives found"
fi
fi
done
# --- Verdict ---
if [[ "$VULN_PHP" -eq 1 && "$VULN_NGINX" -eq 1 ]]; then
RESULT="VULNERABLE"
echo ""
echo "==> VULNERABLE: CVE-2019-11043 — PHP version AND nginx config are exploitable"
elif [[ "$VULN_PHP" -eq 1 && "$VULN_NGINX" -eq 0 ]]; then
RESULT="VULNERABLE"
echo ""
echo "==> VULNERABLE: PHP version is affected. Nginx config may not be exploitable but upgrade PHP immediately."
elif [[ "$VULN_PHP" -eq 0 ]]; then
RESULT="PATCHED"
echo ""
echo "==> PATCHED: PHP version is not in the vulnerable range"
else
echo ""
echo "==> UNKNOWN: Could not determine full exposure"
fi
exit 0If you remember one thing.
try_files $uri =404; nginx config fix or WAF block within 3 days — this afternoon if possible. Per the noisgate remediation SLA, complete the PHP upgrade to 8.x (the only supported branch) within 90 days. Every affected PHP 7.1/7.2/7.3 instance is also missing years of other security patches across dozens of CVEs, so the upgrade is non-negotiable. Prioritize any host in a DMZ or serving customer-facing traffic. If you cannot upgrade PHP within 90 days, formally accept the risk at CISO level and document it — running EOL PHP on the internet is an audit finding on its own.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.