CVE-2026-49286: Pontedilana/php weasyprint PhpWeasyPrint Vulnerable To PHAR Deserialization Vulnerability

HIGH
Advisory Identifier: GHSA-2fmj-p74r-3wjm
CVSS 8.1
CWE-502
Published
Advisory Summary

CVE-2026-49286 is a HIGH (CVSS 8.1) phpweasyprint vulnerable to phar deserialization vulnerability (CWE-502: Deserialization of Untrusted Data) affecting Pontedilana/php weasyprint libraries in the Packagist ecosystem. The issue involves phpweasyprint vulnerable to phar deserialization via output filename (cve-2023-28115 case-insensitive bypass). Remediation is available by upgrading affected packages to version 2.6.0.

CVE-2026-49286 at a Glance

CVE Identifier CVE-2026-49286
GHSA Identifier GHSA-2fmj-p74r-3wjm
Severity HIGH
CVSS v3.1 Base Score 8.1
CWE Classification CWE-502: Deserialization of Untrusted Data
Affected Product Pontedilana/php weasyprint
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 8.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2026-49286

To remediate this vulnerability, upgrade all affected Pontedilana/php weasyprint dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

pontedilana/php-weasyprint fixed: 2.6.0
Upgrade pontedilana/php-weasyprint to 2.6.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for pontedilana/php-weasyprint

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-49286, inspect your project dependencies for Pontedilana/php weasyprint:

inspect dependencies for pontedilana/php-weasyprint

Analyze the terminal output to locate any version of Pontedilana/php weasyprint in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.6.0), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-502: Deserialization of Untrusted Data, where the product deserializes untrusted data without sufficiently ensuring that the resulting data will be valid. In Pontedilana/php weasyprint, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary `pontedilana/php-weasyprint` guarded the output filename against the `phar://` stream wrapper with a case-sensitive blacklist: ```php if (0 === \strpos($filename, 'phar://')) { throw new \InvalidArgumentException('The output file cannot be a phar archive.'); } ``` PHP stream wrappers are **case-insensitive**, so `PHAR://`, `Phar://`, etc. bypass the check and reach `fileExists()` (`file_exists()`) in `prepareOutput()`. On PHP 7 (which the library still supports — PHP 7.4+), this triggers deserialization of a crafted PHAR archive's metadata, leading to remote code execution. This is the patch-bypass of CVE-2023-28115. The same issue and fix were handled upstream in KnpLabs/snappy ([GHSA-92rv-4j2h-8mjj](https://github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj)). ### Affected versions `pontedilana/php-weasyprint` versions `<= 2.5.1` (the case-sensitive guard was introduced in commit `eb8accc`, "Implement countermeasures for CVE-2023-28115"). Patched in: `2.6.0`. ### Privilege required A caller able to control the output filename passed to `generate()` / `generateFromHtml()`, plus the ability to place a PHAR archive on the filesystem (e.g. via an upload). Exploitation of the deserialization requires the server to run PHP < 8. ### Vulnerable code `src/AbstractGenerator.php`, `prepareOutput()`: ```php if (0 === \strpos($filename, 'phar://')) { throw new \InvalidArgumentException('The output file cannot be a phar archive.'); } ``` `strpos($filename, 'phar://')` matches only the exact lowercase string, while the wrapper resolution is case-insensitive — `PHAR://payload.phar` is not caught. ### Proof of concept ```bash # Craft a PHAR with a fast-destruct gadget chain phpggc -f Monolog/RCE1 exec 'touch /tmp/exploit' -p phar -o exploit.phar ``` ```php <?php use Pontedilana\PhpWeasyPrint\Pdf; $pdf = new Pdf('/usr/local/bin/weasyprint'); // Case-altered wrapper bypasses the lowercase 'phar://' blacklist $pdf->generateFromHtml('<h1>POC</h1>', 'PHAR://exploit.phar'); // On PHP < 8, the PHAR metadata is deserialized -> /tmp/exploit is created ``` ### Impact - Remote code execution and filesystem access through PHAR metadata deserialization on PHP < 8, when the output filename is attacker-influenced and a PHAR can be planted. CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (8.1, High) — Critical in deployments running PHP 7 with an upload surface; adjust to your environment. CWE-502 (Deserialization of Untrusted Data). ### Suggested fix Replace the case-sensitive blacklist with a scheme allow-list (`file` / no scheme), comparing the lowercased scheme parsed from the filename: ```php protected const ALLOWED_PROTOCOLS = ['file']; protected function isProtocolAllowed(string $filename): bool { if (false === $parsed = \parse_url($filename)) { throw new \InvalidArgumentException('The filename is not valid.'); } $protocol = isset($parsed['scheme']) ? \strtolower($parsed['scheme']) : 'file'; // ...special-case Windows drive letters (C:\...) as 'file'... return \in_array($protocol, self::ALLOWED_PROTOCOLS, true); } ``` `prepareOutput()` then rejects any non-`file` scheme (`phar`, `PHAR`, `php`, `http`, ...) before `file_exists()` is reached. ### Credit Original vulnerability and patch-bypass reported upstream to KnpLabs/snappy by Rémi Matasse of Synacktiv ([GHSA-92rv-4j2h-8mjj](https://github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj)); identified as applicable to `pontedilana/php-weasyprint`, which mirrors the same code.

CVE-2026-49286 Affected Pontedilana/php weasyprint Versions

1 component(s)
Fixed Versions:
2.6.0
Product / Package Ecosystem Affected Versions Fixed Version
pontedilana/php-weasyprint
Packagist
< 2.6.0
2.6.0

References

Frequently Asked Questions

What is CVE-2026-49286?
CVE-2026-49286 is a security vulnerability in Pontedilana/php weasyprint involving PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass) under CWE-502: Deserialization of Untrusted Data.
Which Pontedilana/php weasyprint versions are affected?
Affected versions include releases prior to 2.6.0 across affected packages: pontedilana/php-weasyprint.
What version fixes CVE-2026-49286?
Upgrading to 2.6.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is pontedilana/php-weasyprint affected?
Yes, pontedilana/php-weasyprint is affected in releases prior to 2.6.0. Upgrade your dependency to 2.6.0 or later.
What is the CVSS score of CVE-2026-49286?
CVE-2026-49286 has a CVSS v3.1 base score of 8.1 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2026-49286?
CVE-2026-49286 is classified under CWE-502: Deserialization of Untrusted Data (The product deserializes untrusted data without sufficiently ensuring that the resulting data will be valid.).
How can I check Packagist dependencies for CVE-2026-49286?
Run the dependency tree command: 'inspect dependencies for pontedilana/php-weasyprint'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-2fmj-p74r-3wjm",
  "modified" : "2026-06-26T22:10:00Z",
  "published" : "2026-06-26T22:10:00Z",
  "aliases" : [ "CVE-2026-49286" ],
  "summary" : "PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)",
  "details" : "### Summary\n\n`pontedilana/php-weasyprint` guarded the output filename against the `phar://` stream wrapper with a case-sensitive blacklist:\n\n```php\nif (0 === \\strpos($filename, 'phar://')) {\n    throw new \\InvalidArgumentException('The output file cannot be a phar archive.');\n}\n```\n\nPHP stream wrappers are **case-insensitive**, so `PHAR://`, `Phar://`, etc. bypass the check and reach `fileExists()` (`file_exists()`) in `prepareOutput()`. On PHP 7 (which the library still supports — PHP 7.4+), this triggers deserialization of a crafted PHAR archive's metadata, leading to remote code execution. This is the patch-bypass of CVE-2023-28115.\n\nThe same issue and fix were handled upstream in KnpLabs/snappy ([GHSA-92rv-4j2h-8mjj](https://github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj)).\n\n### Affected versions\n\n`pontedilana/php-weasyprint` versions `<= 2.5.1` (the case-sensitive guard was introduced in commit `eb8accc`, \"Implement countermeasures for CVE-2023-28115\").\n\nPatched in: `2.6.0`.\n\n### Privilege required\n\nA caller able to control the output filename passed to `generate()` / `generateFromHtml()`, plus the ability to place a PHAR archive on the filesystem (e.g. via an upload). Exploitation of the deserialization requires the server to run PHP < 8.\n\n### Vulnerable code\n\n`src/AbstractGenerator.php`, `prepareOutput()`:\n\n```php\nif (0 === \\strpos($filename, 'phar://')) {\n    throw new \\InvalidArgumentException('The output file cannot be a phar archive.');\n}\n```\n\n`strpos($filename, 'phar://')` matches only the exact lowercase string, while the wrapper resolution is case-insensitive — `PHAR://payload.phar` is not caught.\n\n### Proof of concept\n\n```bash\n# Craft a PHAR with a fast-destruct gadget chain\nphpggc -f Monolog/RCE1 exec 'touch /tmp/exploit' -p phar -o exploit.phar\n```\n\n```php\n<?php\nuse Pontedilana\\PhpWeasyPrint\\Pdf;\n\n$pdf = new Pdf('/usr/local/bin/weasyprint');\n// Case-altered wrapper bypasses the lowercase 'phar://' blacklist\n$pdf->generateFromHtml('<h1>POC</h1>', 'PHAR://exploit.phar');\n// On PHP < 8, the PHAR metadata is deserialized -> /tmp/exploit is created\n```\n\n### Impact\n\n- Remote code execution and filesystem access through PHAR metadata deserialization on PHP < 8, when the output filename is attacker-influenced and a PHAR can be planted.\n\nCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (8.1, High) — Critical in deployments running PHP 7 with an upload surface; adjust to your environment.\n\nCWE-502 (Deserialization of Untrusted Data).\n\n### Suggested fix\n\nReplace the case-sensitive blacklist with a scheme allow-list (`file` / no scheme), comparing the lowercased scheme parsed from the filename:\n\n```php\nprotected const ALLOWED_PROTOCOLS = ['file'];\n\nprotected function isProtocolAllowed(string $filename): bool\n{\n    if (false === $parsed = \\parse_url($filename)) {\n        throw new \\InvalidArgumentException('The filename is not valid.');\n    }\n    $protocol = isset($parsed['scheme']) ? \\strtolower($parsed['scheme']) : 'file';\n    // ...special-case Windows drive letters (C:\\...) as 'file'...\n    return \\in_array($protocol, self::ALLOWED_PROTOCOLS, true);\n}\n```\n\n`prepareOutput()` then rejects any non-`file` scheme (`phar`, `PHAR`, `php`, `http`, ...) before `file_exists()` is reached.\n\n### Credit\n\nOriginal vulnerability and patch-bypass reported upstream to KnpLabs/snappy by Rémi Matasse of Synacktiv ([GHSA-92rv-4j2h-8mjj](https://github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj)); identified as applicable to `pontedilana/php-weasyprint`, which mirrors the same code.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "pontedilana/php-weasyprint"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.6.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.5.1"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pontedilana/php-weasyprint/security/advisories/GHSA-2fmj-p74r-3wjm"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-49286"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pontedilana/php-weasyprint/commit/d1aa487722b5a3cab9b222b85fdb5608a5a550c3"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/pontedilana/php-weasyprint"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pontedilana/php-weasyprint/releases/tag/2.6.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-502" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-26T22:10:00Z",
    "nvd_published_at" : "2026-06-19T18:16:19Z"
  }
}