← Back to Feed CACHED · 2026-07-31 12:11:46 · CACHE_KEY CVE-2026-7260
CVE-2026-7260 · CWE-121 · Disclosed 2026-07-30

Circular symbolic links in phar archives could lead to unbounded recursion

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

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.

"DoS-only crash in PHP phar symlink handling; no code exec, auto-recoverable via PHP-FPM respawn."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Craft malicious phar archive

The attacker creates a tar-based phar archive containing at least two symlinks forming a cycle (e.g., 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.
Conditions required:
  • Knowledge that the target application processes phar archives
Where this breaks in practice:
  • Attacker must know or guess that the target uses phar:// or PharData methods on user-supplied files
STEP 02

Deliver phar to target

The attacker must place the crafted archive where a PHP process will open it. In a web context this means a file-upload endpoint that accepts archives *and* subsequently processes them via 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.
Conditions required:
  • File upload capability or local file placement
  • Target application opens the uploaded file via phar extension
Where this breaks in practice:
  • Most PHP web apps do not use the phar:// wrapper on uploaded files
  • Upload endpoints typically validate MIME types and extensions, rejecting .phar/.tar unless explicitly allowed
  • WAFs and upload scanners may block or quarantine archive uploads
Detection/coverage: Web application firewalls with archive-inspection rules; upload validation logic in application code
STEP 03

Trigger phar processing

When the PHP process opens the crafted archive, 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.
Conditions required:
  • PHP phar extension is loaded (it is compiled-in by default)
  • Application code invokes a phar-aware function on the attacker-controlled path
Where this breaks in practice:
  • 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
Detection/coverage: PHP-FPM error logs show SIGSEGV; SIEM alert on repeated child process crashes; dmesg shows segfault in php-fpm worker
STEP 04

Sustained DoS (optional escalation)

To cause meaningful service disruption, the attacker must repeatedly trigger the crash across multiple PHP-FPM workers. This requires either multiple upload+process cycles or a batch-processing pipeline that iterates over many files. Rate limiting, upload quotas, and FPM's pm.max_children act as natural throttles.
Conditions required:
  • Ability to send repeated requests or upload multiple files
  • No rate limiting on the upload/processing endpoint
Where this breaks in practice:
  • Rate limiting, CAPTCHA, or authentication on upload endpoints
  • PHP-FPM pm.max_children limits 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
Detection/coverage: Spike in 502/503 errors from the reverse proxy; PHP-FPM slow-log and error-log alerts; process monitoring (systemd, monit) flags repeated restarts
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo known exploitation. Not listed in CISA KEV. No threat-intel reports or campaign associations as of 2026-07-31.
Proof of conceptNo 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.
EPSSNot 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 statusNot listed. No CISA deadline applies.
CVSS vectorCVSS: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 versionsPHP < 8.2.33, < 8.3.33, < 8.4.24, < 8.5.9 (all maintained branches)
Fixed versionsPHP 8.2.33, 8.3.33, 8.4.24, 8.5.9 — released 2026-07-31. Fedora and RHEL packages available same day.
Scanning / exposureShodan 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 date2026-07-30 (GHSA), patches released 2026-07-31
CreditCalvin Young (eWalker Consulting HK Limited) and Enoch Chow (Isomorph Cyber)
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.0/10)

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.

HIGH Vulnerability mechanics and impact ceiling (DoS only, confirmed by code review and GHSA)
MEDIUM Reachable attack surface estimate (<1% of PHP installs process untrusted phars)
LOW EPSS score (not yet published; estimate based on vuln class history)

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.

05 · Compensating Control

What to do — in priority order.

  1. Disable the phar extension if unused — Add phar.require_hash=1 and remove extension=phar from php.ini if 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.
  2. Block .phar and .tar uploads 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.
  3. Set PHP-FPM pm.max_children and request_terminate_timeout — Ensure PHP-FPM is configured with a reasonable pm.max_children (e.g., 50–200 depending on server capacity) and request_terminate_timeout to limit the duration of any single request. This contains the blast radius of repeated crash attempts.
  4. Monitor for repeated SIGSEGV in PHP-FPM workers — Create a SIEM alert on SIGSEGV or segfault in /var/log/php-fpm/*.log and dmesg. More than 3 crashes in 5 minutes from the same endpoint warrants investigation — it could indicate active exploitation or mask a more serious attack.
What doesn't work
  • 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_basedir restrictions — 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.
06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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 0
07 · Bottom Line

If you remember one thing.

TL;DR
This is a MEDIUM severity DoS bug — no code execution, no data exposure, auto-recovering under PHP-FPM. There is no noisgate mitigation SLA for MEDIUM; go straight to the 365-day noisgate remediation SLA and fold the PHP update (8.2.33 / 8.3.33 / 8.4.24 / 8.5.9) into your next scheduled maintenance window. If you have PHP hosts that accept untrusted archive uploads *and* process them via 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

  1. GHSA-vc5h-9ppw-p5f3 — GitHub Security Advisory
  2. PHP 8.4 branch fix commit
  3. PHP 8.3.33 branch fix commit
  4. PHP 8.4.24 tagged release fix
  5. PHP ChangeLog
  6. Fedora/RHEL package updates for PHP 8.2.33–8.5.9
  7. GBHackers — PHP Patches 3 Security Flaws
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.