A booby-trapped zip file that reboots one worker bee but never breaches the hive
CVE-2026-7260 is a stack-exhaustion crash in PHP's ext/phar extension. The function phar_get_link_source() in ext/phar/util.c follows symbolic links inside tar-based phar archives without any depth limit or cycle detection. A crafted phar containing two symlinks pointing at each other causes unbounded C-stack recursion → segfault → PHP process termination. All maintained PHP branches prior to 8.2.33, 8.3.33, 8.4.24, and 8.5.9 are affected. The impact is availability only — no memory corruption leading to code execution, no information disclosure, no integrity violation.
The GHSA advisory (GHSA-vc5h-9ppw-p5f3) rates this Moderate at CVSS 5.5 with a local attack vector and required user interaction. That feels right. The crash kills a single PHP worker; under PHP-FPM (the dominant production deployment model), the master process respawns the worker in milliseconds. Sustained DoS requires repeated delivery of malicious phars, and the attack surface — applications that open untrusted .phar or .tar archives via the phar:// stream wrapper — is a narrow slice of the PHP install base. This is a real bug, but the ceiling is a transient service hiccup, not a breach.
4 steps from start to impact.
Craft malicious phar archive
a → b, b → a). Standard tar tooling or a trivial Python script can produce this artifact in seconds. No special tooling or exploit framework is needed.- Knowledge that the target application processes phar archives
- Attacker must know or guess that the target uses phar:// or PharData methods on user-supplied files
Deliver phar to target
phar://, PharData::__construct(), or similar. In a CLI context the attacker needs local access or social engineering to get an admin to run a phar-consuming script against the file.- File upload capability or local file placement
- Target application opens the uploaded file via phar extension
- Most PHP web apps do not use the phar:// wrapper on uploaded files
- Upload endpoints typically validate MIME types and extensions, rejecting
.phar/.tarunless explicitly allowed - WAFs and upload scanners may block or quarantine archive uploads
Trigger phar processing
phar_get_link_source() enters unbounded recursion following the circular symlinks. The C call stack grows until it hits the OS stack size limit (typically 8 MB on Linux), at which point the process receives SIGSEGV and terminates.- PHP phar extension is loaded (it is compiled-in by default)
- Application code invokes a phar-aware function on the attacker-controlled path
- PHP-FPM immediately respawns the crashed worker — downtime is sub-second per request
- A single crash affects one worker process, not the entire server
phar.readonly=1(the default) does not prevent *reading* phars, but many apps never read phars at all
dmesg shows segfault in php-fpm workerSustained DoS (optional escalation)
pm.max_children act as natural throttles.- Ability to send repeated requests or upload multiple files
- No rate limiting on the upload/processing endpoint
- Rate limiting, CAPTCHA, or authentication on upload endpoints
- PHP-FPM
pm.max_childrenlimits concurrent workers; crash/respawn cycle adds latency but doesn't exhaust the pool unless attack rate exceeds respawn rate - Ops teams will notice repeated SIGSEGV in minutes
The supporting signals.
| In-the-wild exploitation | No known exploitation. Not listed in CISA KEV. No threat-intel reports or campaign associations as of 2026-07-31. |
|---|---|
| Proof of concept | No public weaponized PoC. The fix commit references test cases with circular symlinks (tests/phar/circular_symlink.phpt), which effectively demonstrate the trigger. Crafting a malicious tar is trivial with standard tools. |
| EPSS | Not yet scored (CVE published 2026-07-30, EPSS ingestion typically lags 1–3 days). Expected to be low (<5th percentile) given local vector and DoS-only impact. |
| KEV status | Not listed. No CISA deadline applies. |
| CVSS vector | CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H — Local vector, user interaction required, availability-only impact. No confidentiality or integrity loss. |
| Affected versions | PHP < 8.2.33, < 8.3.33, < 8.4.24, < 8.5.9 (all maintained branches) |
| Fixed versions | PHP 8.2.33, 8.3.33, 8.4.24, 8.5.9 — released 2026-07-31. Fedora and RHEL packages available same day. |
| Scanning / exposure | Shodan indexes ~30M PHP-powered HTTP servers globally. However, the *reachable* population is the subset that (a) accepts archive uploads AND (b) processes them via phar:// — estimated at well under 1% of PHP deployments. |
| Disclosure date | 2026-07-30 (GHSA), patches released 2026-07-31 |
| Credit | Calvin Young (eWalker Consulting HK Limited) and Enoch Chow (Isomorph Cyber) |
noisgate verdict.
The single most decisive factor is that impact is availability-only with automatic recovery — a crashed PHP-FPM worker respawns in milliseconds, so the blast radius of a successful exploit is a transient request failure, not a service outage or data breach. No code execution, privilege escalation, or data exfiltration path exists in this chain.
Why this verdict
- DoS-only, no code execution: The crash is a clean SIGSEGV from stack exhaustion. There is no heap corruption, no controlled overwrite, and no path to RCE. The impact ceiling is process termination.
- Auto-recovery blunts operational impact: PHP-FPM (used by >90% of production PHP deployments) respawns crashed workers automatically. A single exploit attempt kills one request, not the service. Sustained DoS requires repeated delivery at a rate exceeding respawn — a high bar against any rate-limited endpoint.
- Narrow reachable surface: The attack requires the target to open an attacker-supplied file via the phar extension. Most PHP applications never invoke
phar://on user-uploaded content. The exposed population is a small fraction of the ~30M PHP servers indexed by Shodan. - Local vector + user interaction: CVSS classifies this as AV:L/UI:R. In web scenarios, an upload-to-phar-processing chain partially satisfies this remotely, but that pipeline is uncommon and adds friction.
- Role multiplier: PHP runs on web servers (typical role) and occasionally on CI/CD workers or CLI batch processors. Even in a high-value web-tier role, the outcome is a transient worker crash — not domain compromise, not data exfiltration, not supply-chain pivot. The blast radius is host-local, single-process, auto-recovering. No high-value role elevates this beyond MEDIUM because the impact type (availability only, self-healing) caps the damage regardless of where PHP runs.
Why not higher?
Upgrading to HIGH would require either a code-execution path or a persistent denial-of-service that survives process restart. Neither exists here. The auto-respawn behavior of PHP-FPM means even a successful exploit has sub-second impact per request. There is no KEV listing, no active exploitation, and no evidence of weaponization. The attack surface (apps that phar-process uploads) is narrow enough that fleet-wide risk is minimal.
Why not lower?
Downgrading to LOW would undercount the ease of crafting the payload (trivial) and the fact that the phar extension is compiled-in by default on every PHP installation. While the *reachable* surface is small, PHP's install base is enormous, so even a small percentage represents meaningful absolute numbers. A crash is still a crash — it produces log noise, triggers alerts, and could mask other attacks. The 5.5 GHSA score is a reasonable anchor; dropping below 5.0 is not warranted.
What to do — in priority order.
- Disable the phar extension if unused — Add
phar.require_hash=1and removeextension=pharfromphp.iniif your application does not use phar archives. This eliminates the attack surface entirely. Since there is no noisgate mitigation SLA for MEDIUM, this is an optional hardening step — apply it as part of your standard configuration review. - Block
.pharand.taruploads at the WAF/reverse proxy — Configure your WAF or upload handler to reject files with phar-associated extensions and MIME types (application/x-phar,application/x-tar). This prevents delivery of the malicious payload to PHP. Implement as part of your upload allow-list policy. - Set PHP-FPM
pm.max_childrenandrequest_terminate_timeout— Ensure PHP-FPM is configured with a reasonablepm.max_children(e.g., 50–200 depending on server capacity) andrequest_terminate_timeoutto limit the duration of any single request. This contains the blast radius of repeated crash attempts. - Monitor for repeated SIGSEGV in PHP-FPM workers — Create a SIEM alert on
SIGSEGVorsegfaultin/var/log/php-fpm/*.loganddmesg. More than 3 crashes in 5 minutes from the same endpoint warrants investigation — it could indicate active exploitation or mask a more serious attack.
phar.readonly=1— This is the default and it prevents *writing* phars, but it does not prevent reading/opening them. The vulnerability is triggered on read, so this setting provides zero protection.open_basedirrestrictions — These limit which directories PHP can access but do not prevent processing of a phar file that has already been uploaded to an allowed directory.- Network-level controls (firewall, segmentation) — The attack payload is an uploaded file, not a network exploit. Blocking ports or IPs does not help once the file reaches the PHP process.
Crowdsourced verification payload.
Run this script on each PHP host to check whether the installed PHP version is vulnerable. Execute as any user with access to the php binary: bash check_cve_2026_7260.sh. No special privileges required.
#!/usr/bin/env bash
# check_cve_2026_7260.sh
# Checks if the installed PHP version is vulnerable to CVE-2026-7260
# (phar circular symlink stack overflow)
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PHP_BIN="${1:-php}"
if ! command -v "$PHP_BIN" &>/dev/null; then
echo "UNKNOWN: php binary not found at '$PHP_BIN'"
exit 2
fi
VERSION=$($PHP_BIN -r 'echo PHP_VERSION;' 2>/dev/null)
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN: could not determine PHP version"
exit 2
fi
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3 | sed 's/[^0-9].*//')
echo "Detected PHP version: $VERSION"
# Fixed versions: 8.2.33, 8.3.33, 8.4.24, 8.5.9
# Affected: < 8.2.33, < 8.3.33, < 8.4.24, < 8.5.9
if [[ "$MAJOR" -lt 8 ]]; then
echo "VULNERABLE: PHP $VERSION — PHP 7.x and below are end-of-life and contain this flaw"
exit 1
fi
if [[ "$MAJOR" -eq 8 ]]; then
case "$MINOR" in
2)
if [[ "$PATCH" -ge 33 ]]; then
echo "PATCHED: PHP $VERSION contains the fix for CVE-2026-7260"
exit 0
else
echo "VULNERABLE: PHP $VERSION — upgrade to >= 8.2.33"
exit 1
fi
;;
3)
if [[ "$PATCH" -ge 33 ]]; then
echo "PATCHED: PHP $VERSION contains the fix for CVE-2026-7260"
exit 0
else
echo "VULNERABLE: PHP $VERSION — upgrade to >= 8.3.33"
exit 1
fi
;;
4)
if [[ "$PATCH" -ge 24 ]]; then
echo "PATCHED: PHP $VERSION contains the fix for CVE-2026-7260"
exit 0
else
echo "VULNERABLE: PHP $VERSION — upgrade to >= 8.4.24"
exit 1
fi
;;
5)
if [[ "$PATCH" -ge 9 ]]; then
echo "PATCHED: PHP $VERSION contains the fix for CVE-2026-7260"
exit 0
else
echo "VULNERABLE: PHP $VERSION — upgrade to >= 8.5.9"
exit 1
fi
;;
*)
# 8.6+ presumably includes the fix
echo "PATCHED: PHP $VERSION — version is newer than all affected branches"
exit 0
;;
esac
fi
# PHP 9+ presumably includes the fix
echo "PATCHED: PHP $VERSION — version is newer than all affected branches"
exit 0If you remember one thing.
phar://, prioritize those first — disable the phar extension or block phar/tar uploads at the WAF as a low-effort hardening step this week. For the rest of your fleet, this rides the normal patch train. Do not let this CVE bump higher-severity items down the queue.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.