CVE-2026-45034 - PHPSpreadsheet PHAR wrapper patch bypass
PHPSpreadsheet’s fix for CVE-2026-34084 rejected common stream-wrapper paths by
checking the scheme returned by parse_url. The bypass uses wrapper-shaped
paths such as phar:///..., where PHP’s stream layer still treats the input as
a PHAR wrapper even though the helper’s scheme check can miss it.
On PHP 7.x, touching a PHAR path can deserialize PHAR metadata and trigger attacker-controlled magic methods. On PHP 8.x, the same PHPSpreadsheet path is less directly exploitable at this layer, but wrapper-style spreadsheet paths still violate the intended file boundary and should be rejected before the library attempts to inspect or load them.
When to use it
Use this recipe when a PHP application imports spreadsheets with
phpoffice/phpspreadsheet, especially from uploads, URLs, queues, or
user-selected paths. It supports source-code remediation, stream-wrapper
containment, file-ingestion audit, and evidence that PHAR or wrapper-style
paths are rejected before spreadsheet loading.
Inputs
- PHPSpreadsheet version, PHP runtime version, package lockfiles, spreadsheet import routes/jobs, upload storage, and path allow-list policy.
- Source paths that accept spreadsheet paths, resolve upload files, call reader APIs, inspect wrappers, or log import errors.
- Regression fixtures for
phar://, triple-slash wrapper shapes, absolute paths, benign uploaded files, PHP 7/8 behavior, and expected rejection. - Boundary evidence: who can submit spreadsheets, where files are stored, magic method gadget exposure, logs, and cleanup owner.
Affected versions
- Vulnerable package:
phpoffice/phpspreadsheet <=1.30.4 - Fixed package:
phpoffice/phpspreadsheet 1.30.5+ - Related advisory: CVE-2026-34084 / GHSA-q4q6-r8wh-5cgh
- Highest-risk runtime: PHP 7.x applications that load user-controlled spreadsheet paths
- Affected input shape: wrapper paths such as
phar:///...supplied to spreadsheet import, preview, conversion, or validation code
Indicator-of-exposure
- The repository depends on
phpoffice/phpspreadsheet <=1.30.4or vendors the vulnerable helper. - Application code calls
IOFactory::load, readers, import services, preview jobs, validators, background converters, or upload processors with paths that can be influenced by users, tenants, email attachments, storage object names, queues, webhooks, or agent output. - PHP 7.x is still used in production, CI, batch import workers, or legacy containers.
- File validation relies on
parse_url(..., PHP_URL_SCHEME)or only rejectsphar://with exactly two slashes. - Uploaded files, temporary files, object-store keys, or import paths are accepted before canonicalization into a known local directory.
Quick checks:
rg -n "phpoffice/phpspreadsheet|PhpSpreadsheet|IOFactory::load|Reader|Spreadsheet|prohibitWrappers|parse_url\\(.*PHP_URL_SCHEME|phar://|upload|import|preview|convert" .
composer show phpoffice/phpspreadsheet
composer why phpoffice/phpspreadsheet
rg -n "php:7|PHP_VERSION|7\\.4|7\\.3|7\\.2|phar\\.readonly|Phar::getMetadata|realpath|://|is_file\\(|file_exists\\(" Dockerfile* compose*.yml .github config scripts src app . 2>/dev/null
Windows:
rg -n "phpoffice/phpspreadsheet|PhpSpreadsheet|IOFactory::load|Reader|Spreadsheet|prohibitWrappers|parse_url\\(.*PHP_URL_SCHEME|phar://|upload|import|preview|convert" .
composer show phpoffice/phpspreadsheet
composer why phpoffice/phpspreadsheet
rg -n "php:7|PHP_VERSION|7\\.4|7\\.3|7\\.2|phar\\.readonly|Phar::getMetadata|realpath|://|is_file\\(|file_exists\\(" Dockerfile* compose*.yml .github config scripts src app .
Do not build attacker PHAR files, run PHAR deserialization proofs, call
Phar::getMetadata on untrusted files, or print uploaded spreadsheet contents
while validating.
Remediation strategy
- Upgrade every controlled
phpoffice/phpspreadsheetdependency, lockfile, vendor tree, image, SBOM, generated dependency report, and deployment manifest to1.30.5+. - Add application-level wrapper rejection before spreadsheet loading. Reject any
caller-controlled filename or storage key containing
://, includingphar:///, beforeIOFactory::load,is_file,file_exists, readers, or preview/conversion jobs touch the path. - Prefer server-generated local temporary file paths. Resolve with
realpathafter upload/storage retrieval and verify the path stays inside the intended import directory. - Treat PHP 7.x spreadsheet workers as urgent: upgrade the library and plan PHP runtime migration where possible because PHAR metadata behavior makes wrapper mistakes materially worse.
- Review custom
prohibitWrappers, upload validation, object-store import, and queued conversion code for equivalentparse_urlwrapper-detection bugs. - Rotate credentials and review imported files, job logs, and generated outputs if untrusted spreadsheet paths were accepted on PHP 7.x workers.
The prompt
You are remediating CVE-2026-45034 / GHSA-87m4-826x-3crx, a critical
PHPSpreadsheet bypass of the CVE-2026-34084 stream-wrapper fix where
`phar:///...`-style paths can pass wrapper checks. Produce exactly one output:
- A reviewer-ready PR/change request that upgrades PHPSpreadsheet, rejects all
wrapper-style spreadsheet paths before file access, hardens upload/import
boundaries, refreshes generated artifacts, and documents operator cleanup, or
- TRIAGE.md if this repository does not control an affected PHPSpreadsheet
dependency, spreadsheet importer, conversion worker, image, or deployment.
## Rules
- Scope only CVE-2026-45034 / GHSA-87m4-826x-3crx, the related
CVE-2026-34084 wrapper fix, and directly related spreadsheet import
boundaries.
- Treat uploaded spreadsheets, temporary paths, object-store keys, tenant files,
generated previews, conversion outputs, PHAR metadata, logs, and application
secrets as sensitive.
- Do not build malicious PHARs, execute deserialization proofs, call
`Phar::getMetadata` on untrusted input, or print uploaded file contents.
- Do not remove spreadsheet import validation, MIME checks, antivirus scanning,
authorization, or audit logs just to suppress the advisory.
- Do not auto-merge.
## Steps
1. Inventory every controlled PHPSpreadsheet reference: `composer.json`,
`composer.lock`, vendored code, Dockerfiles, Compose files, CI images,
import workers, preview/conversion services, upload handlers, SBOMs,
generated dependency reports, and deployment docs.
2. Determine every resolved `phpoffice/phpspreadsheet` version. A target is
vulnerable if it resolves to `<=1.30.4`.
3. Determine every spreadsheet load path: `IOFactory::load`, reader factories,
upload validation, queued conversion, email attachment ingestion,
object-store import, preview generation, CLI import commands, and agent/tool
generated import jobs.
4. Determine the PHP runtime for each load path. Flag PHP 7.x workers as
highest risk.
5. If this repository does not control the vulnerable dependency or any
spreadsheet-loading runtime, stop with `TRIAGE.md` listing checked files,
external owner if known, and required fixed version `1.30.5+`.
6. Upgrade all controlled `phpoffice/phpspreadsheet` references to `1.30.5+`.
Refresh `composer.lock`, vendor trees if committed, container layers, SBOMs,
generated reports, deployment manifests, and docs.
7. Add application-level wrapper rejection before any file operation:
- reject any user-controlled path or storage key containing `://`;
- reject `phar:///`, `phar://`, `php://`, `data://`, `expect://`, and other
stream-wrapper variants;
- do not depend on `parse_url(..., PHP_URL_SCHEME)` alone;
- avoid calling `is_file`, `file_exists`, or readers on untrusted wrapper
strings.
8. Resolve accepted files to server-owned local paths:
- store uploads under a controlled import directory;
- call `realpath` after storage retrieval;
- verify the resolved path stays inside the import directory;
- pass only the resolved local path to PHPSpreadsheet.
9. Add safe regression tests:
- vulnerable package versions are absent;
- `phar:///tmp/test.phar/sheet.xlsx` and other wrapper-looking strings are
rejected without touching the filesystem;
- normal uploaded spreadsheets still import from resolved local temp paths;
- PHP 7.x worker images are patched or explicitly retired;
- error messages and logs do not expose tenant paths, file contents, or
secrets.
10. Add a PR body section named `CVE-2026-45034 operator actions` that states:
- PHPSpreadsheet versions before and after;
- which spreadsheet load paths were patched or triaged;
- whether any PHP 7.x import workers remain;
- where wrapper-style paths are rejected;
- whether imported files, conversion outputs, logs, or credentials need
review;
- which validation commands passed.
11. Run available validation: `composer install`, lockfile audit, unit and
import tests, upload validation tests, static analysis, container build,
SBOM refresh, dependency/security scans, and non-secret smoke checks.
12. Use PR title:
`fix(sec): remediate CVE-2026-45034 in PHPSpreadsheet`.
## Stop conditions
- No affected PHPSpreadsheet dependency, vendored copy, import path, image, or
deployment is controlled by this repository.
- A fixed version cannot be consumed without a broader PHP/runtime migration.
- The only vulnerable runtime is owned by another team or vendor; document the
owner and required fixed version in `TRIAGE.md`.
- Verification would require malicious PHAR generation, deserialization,
reading tenant files, or exposing uploaded spreadsheet contents.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.
Output contract
- A reviewer-ready PR or change request that upgrades PHPSpreadsheet, rejects all wrapper-style paths before loading, adds PHAR regression checks, and documents ingestion cleanup.
- Or a
TRIAGE.mdfile that lists inspected files, owner, observed version, ingestion boundary, wrapper policy, required fix, and residual risk. - The output must include exact validation commands and must not load real PHAR payloads, expose uploaded customer files, or run production imports.
Verification - what the reviewer looks for
- No controlled lockfile, vendor tree, image, SBOM, or generated report resolves
phpoffice/phpspreadsheet <=1.30.4. - Spreadsheet import paths reject
://wrapper-looking strings before any file operation or PHPSpreadsheet reader call. - Accepted uploads are copied or materialized to server-owned local paths,
resolved with
realpath, and bounded to the import directory. - Tests cover
phar:///triple-slash paths without building or opening a PHAR. - Operator notes identify any remaining PHP 7.x import workers and cleanup needed for untrusted imports.
Watch for
- Updating
composer.jsonwhilecomposer.lock, committedvendor/, container images, or worker deployments still resolve the vulnerable package. - Blocking only
phar://while allowingphar:///or other wrapper schemes. - Checking wrapper strings after
is_file,file_exists, MIME detection, or reader creation has already touched the path. - Treating PHP 8.x as a full fix while still accepting wrapper-style paths into spreadsheet import workflows.
Related recipes
- Source code injection sink audit
- Source code secrets and data exposure audit
- OWASP Top 10 2026 audit
- SAST finding triage and fix
References
- GitHub Advisory Database: https://github.com/advisories/GHSA-87m4-826x-3crx
- Related PHPSpreadsheet advisory: https://github.com/advisories/GHSA-q4q6-r8wh-5cgh
- Source repository: https://github.com/PHPOffice/PhpSpreadsheet