NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐘
🐘 Packagist
Not in CISA KEV
LOW severity

CVE-2026-49358 — php-weasyprint

LOWFix: pontedilana/php-weasyprint@6d328ff

CVE-2026-49358 is a low-severity (CVSS 3) CWE-73 vulnerability in pontedilana/php-weasyprint. A fix is available for pontedilana/php-weasyprint — see the affected versions and patch details below.

PhpWeasyPrint vulnerable to arbitrary file deletion at shutdown via public $temporaryFiles

Also known asGHSA-5g9f-cwwg-4p8g
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 7, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-49358.

EPSS Exploitation Probability

via FIRST.org ↗
0.2%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs6th percentile — riskier than 6% of all scored CVEsHighest risk
0.00%0.22%0.44%0.67%0.1%0.2%Jul 26Oct 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

1 pkg affected
🐘pontedilana/php-weasyprint

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.

Description

Summary

AbstractGenerator::$temporaryFiles is a public array, and removeTemporaryFiles() — invoked from __destruct() and from a registered shutdown function — calls unlink() on every entry without verifying that the path is contained within the temporary folder. Any code holding a reference to a generator instance can push an arbitrary path into the array and have it deleted on script shutdown.

This mirrors the KnpLabs/snappy issue GHSA-87qc-37cw-84h4, patched in snappy 1.7.2.

Affected versions

pontedilana/php-weasyprint versions <= 2.5.1.

Patched in: 2.6.0.

Vulnerable code

src/AbstractGenerator.php:

public array $temporaryFiles = [];

// ...

public function removeTemporaryFiles(): void
{
    foreach ($this->temporaryFiles as $file) {
        $this->unlink($file);
    }
}

No path-containment check: whatever path is present in $temporaryFiles at shutdown is unlinked.

Proof of concept

<?php
use Pontedilana\PhpWeasyPrint\Pdf;

$pdf = new Pdf();
$pdf->temporaryFiles[] = '/var/www/html/.env';

// On shutdown, removeTemporaryFiles() deletes /var/www/html/.env.

Impact

  • Arbitrary file deletion bound to script shutdown, scoped to the privileges of the PHP process user.
  • Not directly exploitable on its own (the attacker already needs to influence the property in the same request). The risk is amplification: chained with a separate disclosure bug it enables leak-then-delete-to-cover-tracks, and any deserialization/property-oriented gadget that reaches this property becomes a generic file-delete primitive.

CWE-73 (External Control of File Name or Path).

Suggested fix

Only delete files that actually live inside the temporary folder, comparing canonical (realpath) paths:

public function removeTemporaryFiles(): void
{
    $temporaryFolderPath = \realpath($this->getTemporaryFolder());
    if (false === $temporaryFolderPath) {
        return;
    }
    $temporaryFolderPath = \rtrim($temporaryFolderPath, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR;

    foreach ($this->temporaryFiles as $file) {
        $filePath = \realpath($file);
        if (false === $filePath || 0 !== \strncmp($filePath, $temporaryFolderPath, \strlen($temporaryFolderPath))) {
            continue;
        }
        $this->unlink($file);
    }
}

(The trailing directory separator prevents a sibling folder such as /tmpevil from matching /tmp; strncmp is used instead of str_starts_with to keep PHP 7.4 compatibility.)

Credit

Reported upstream to KnpLabs/snappy (GHSA-87qc-37cw-84h4); identified as applicable to pontedilana/php-weasyprint, which mirrors the same code.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐘Packagistpontedilana/php-weasyprintall versions2.6.0composer require pontedilana/php-weasyprint:^2.6.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for pontedilana/php-weasyprint, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update pontedilana/php-weasyprint to 2.6.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-49358 is resolved across your whole dependency graph.

  3. Workarounds

    Do not deserialise data from untrusted sources: where the format allows it, restrict deserialisation to an explicit allowlist of expected types, and prefer a data-only format (JSON, Protobuf) over one that can reconstruct arbitrary objects until you can upgrade.

Frequently Asked Questions

### Summary `AbstractGenerator::$temporaryFiles` is a public array, and `removeTemporaryFiles()` — invoked from `__destruct()` and from a registered shutdown function — calls `unlink()` on every entry without verifying that the path is contained within the temporary folder. Any code holding a reference to a generator instance can push an arbitrary path into the array and have it deleted on script shutdown. This mirrors the KnpLabs/snappy issue [GHSA-87qc-37cw-84h4](https://github.com/KnpLabs/snappy/security/advisories/GHSA-87qc-37cw-84h4), patched in snappy 1.7.2. ### Affected versions `po
O3 Security · Impact-Aware SCA

Is CVE-2026-49358 in your dependencies?

Find it across Packagist, including transitive dependencies.

CVE-2026-49358: php-weasyprint — Fixed in 2.6.0