GHSA-2fmj-p74r-3wjm

Suggest an improvement
Source
https://github.com/advisories/GHSA-2fmj-p74r-3wjm
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-2fmj-p74r-3wjm/GHSA-2fmj-p74r-3wjm.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-2fmj-p74r-3wjm
Aliases
  • CVE-2026-49286
Published
2026-06-26T22:10:00Z
Modified
2026-06-26T22:15:08.673671284Z
Severity
  • 8.1 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H CVSS Calculator
Summary
PhpWeasyPrint vulnerable to PHAR deserialization via output filename (CVE-2023-28115 case-insensitive bypass)
Details

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.

Database specific
{
    "nvd_published_at": "2026-06-19T18:16:19Z",
    "severity": "HIGH",
    "cwe_ids": [
        "CWE-502"
    ],
    "github_reviewed_at": "2026-06-26T22:10:00Z",
    "github_reviewed": true
}
References

Affected packages

Packagist / pontedilana/php-weasyprint

Package

Name
pontedilana/php-weasyprint
Purl
pkg:composer/pontedilana%2Fphp-weasyprint

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
2.6.0

Affected versions

0.*
0.9.0
0.10.0
0.10.1
0.11.0
0.12.0
0.13.0
1.*
1.0.0
1.0.1
1.1.0
1.1.1
1.2.0
1.3.0
1.4.0
1.5.0
2.*
2.0.0
2.1.0
2.2.0
2.3.0
2.4.0
2.5.0
2.5.1

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-2fmj-p74r-3wjm/GHSA-2fmj-p74r-3wjm.json"
last_known_affected_version_range
"<= 2.5.1"