GHSA-5g9f-cwwg-4p8g

Suggest an improvement
Source
https://github.com/advisories/GHSA-5g9f-cwwg-4p8g
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-5g9f-cwwg-4p8g/GHSA-5g9f-cwwg-4p8g.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-5g9f-cwwg-4p8g
Aliases
  • CVE-2026-49358
Published
2026-06-26T22:10:51Z
Modified
2026-06-26T22:15:08.627845924Z
Severity
  • 3.0 (Low) CVSS_V3 - CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:L CVSS Calculator
Summary
PhpWeasyPrint vulnerable to arbitrary file deletion at shutdown via public $temporaryFiles
Details

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.

Database specific
{
    "nvd_published_at": "2026-06-19T15:16:35Z",
    "cwe_ids": [
        "CWE-73"
    ],
    "github_reviewed": true,
    "severity": "LOW",
    "github_reviewed_at": "2026-06-26T22:10:51Z"
}
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

last_known_affected_version_range
"<= 2.5.1"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-5g9f-cwwg-4p8g/GHSA-5g9f-cwwg-4p8g.json"