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.4 or 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 rejects phar:// 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/phpspreadsheet dependency, lockfile, vendor tree, image, SBOM, generated dependency report, and deployment manifest to 1.30.5+.
  • Add application-level wrapper rejection before spreadsheet loading. Reject any caller-controlled filename or storage key containing ://, including phar:///, before IOFactory::load, is_file, file_exists, readers, or preview/conversion jobs touch the path.
  • Prefer server-generated local temporary file paths. Resolve with realpath after 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 equivalent parse_url wrapper-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.md file 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.json while composer.lock, committed vendor/, container images, or worker deployments still resolve the vulnerable package.
  • Blocking only phar:// while allowing phar:/// 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.

References