CVE-2026-49359: Pontedilana/php weasyprint PhpWeasyPrint Vulnerable To SSRF And Vulnerability

MODERATE
Advisory Identifier: GHSA-x8g9-h984-pc36
CVSS 6.5
CWE-918
Published
Advisory Summary

CVE-2026-49359 is a MODERATE (CVSS 6.5) phpweasyprint vulnerable to ssrf and vulnerability (CWE-918: Server-Side Request Forgery (SSRF)) affecting Pontedilana/php weasyprint libraries in the Packagist ecosystem. The issue involves phpweasyprint vulnerable to ssrf and local file disclosure via the attachment option. Remediation is available by upgrading affected packages to version 2.6.0.

CVE-2026-49359 at a Glance

CVE Identifier CVE-2026-49359
GHSA Identifier GHSA-x8g9-h984-pc36
Severity MODERATE
CVSS v3.1 Base Score 6.5
CWE Classification CWE-918: Server-Side Request Forgery (SSRF)
Affected Product Pontedilana/php weasyprint
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 6.5

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

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

How to Fix CVE-2026-49359

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-49359, 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-918: Server-Side Request Forgery (SSRF), where the web server receives a url or similar request from an upstream component and retrieves the contents of this url, but it does not sufficiently ensure that the request is being sent to the expected destination. 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` fetches the content of option values server-side via `file_get_contents()` when the value looks like a URL, without restricting the URL scheme. The `attachment` option of `Pdf` is the reachable sink: any value that passes `isOptionUrl()` (`filter_var(..., FILTER_VALIDATE_URL)`) is downloaded by the PHP process and embedded into the generated PDF. Because `FILTER_VALIDATE_URL` accepts `http`, `https`, `ftp`, `file` and PHP stream wrappers such as `php://`, an attacker who can influence the `attachment` value reaches both a **Server-Side Request Forgery** primitive (e.g. internal HTTP endpoints, cloud metadata) and a **local file disclosure** primitive (`file://`, `php://filter/...`), with the fetched bytes exfiltrated as a PDF attachment. This is the same class of issue KnpLabs/snappy patched for its `xsl-style-sheet` option in [GHSA-c5fp-p67m-gq56](https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56). The library is documented as a one-to-one substitute for KnpLabs/snappy and shares the same code shape. ### Affected versions `pontedilana/php-weasyprint` versions `<= 2.5.1`. Patched in: `2.6.0`. ### Privilege required Any caller that can influence the `attachment` option value handed to `Pdf::generate()` / `Pdf::getOutput()` / `setOption('attachment', ...)`. Typical reach paths: a value sourced from a request parameter, a per-tenant configuration row, or any user-controllable field that flows into the attachment list. ### Vulnerable code `src/Pdf.php` — `isOptionUrl()` accepts any well-formed URL regardless of scheme: ```php protected function isOptionUrl($option): bool { return false !== \filter_var($option, \FILTER_VALIDATE_URL); } ``` `src/Pdf.php` — `handleArrayOptions()` fetches the URL content for the `attachment` option: ```php $fetchUrlContent = 'attachment' === $option && $this->isOptionUrl($item); if ($saveToTempFile || $fetchUrlContent) { $fileContent = $fetchUrlContent ? \file_get_contents($item) : $item; $returnOptions[] = $this->createTemporaryFile($fileContent, $this->optionsWithContentCheck[$option] ?? 'temp'); } ``` `FILTER_VALIDATE_URL` returns truthy for `http://`, `https://`, `ftp://`, `file://localhost/...`, and `php://filter/...`, so `\file_get_contents()` is invoked on attacker-chosen schemes with no allow-list. ### Proof of concept ```php <?php use Pontedilana\PhpWeasyPrint\Pdf; $pdf = new Pdf('/usr/local/bin/weasyprint'); // Attacker-controlled attachment value (e.g. from a request / tenant config): // SSRF: http://169.254.169.254/latest/meta-data/iam/security-credentials/ // Local file read: php://filter/convert.base64-encode/resource=/etc/passwd $attachment = $_GET['doc']; $pdf->generate('page.html', 'out.pdf', [ 'attachment' => $attachment, ]); // The bytes fetched server-side by file_get_contents() are embedded in out.pdf, // allowing the attacker to read internal HTTP responses or local files. ``` ### Impact - **SSRF**: the server fetches arbitrary `http(s)`/`ftp` URLs, reaching internal-only services, link-local metadata endpoints, etc. - **Local file / wrapper disclosure**: `php://filter/...` (and similar) let an attacker read and exfiltrate local file content inside the generated PDF. - Affects any consumer that does not fully control the `attachment` option value. Note: passing a plain local path (e.g. `/etc/passwd`) or a `file://` path that resolves to an existing file is handled as a normal local attachment and is **not** the issue addressed here — that is the documented local-attachment feature (callers must not pass untrusted input to the option). The fix specifically removes the server-side fetch amplification through non-`http(s)` schemes. CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (6.5, Medium) — adjust `PR`/`S`/`A` to the consuming application's reachability (e.g. `PR:N` if the attachment value is reachable from an unauthenticated surface). CWE-918 (Server-Side Request Forgery); secondary CWE-22 (Improper Limitation of a Pathname) for the wrapper-based file read. ### Suggested fix Restrict the schemes the library will fetch to an allow-list (`http`, `https` by default), and treat any other scheme as inline content instead of fetching it: ```php private array $allowedSchemes = ['http', 'https']; // new optional 4th constructor argument: ?array $allowedSchemes = null protected function isOptionUrl($option): bool { $url = \parse_url((string)$option); return false !== $url && isset($url['scheme']) && \in_array(\strtolower($url['scheme']), $this->allowedSchemes, true); } ``` A value with a non-allowed scheme (`file://`, `php://`, `ftp://`, ...) is then never passed to `file_get_contents()`. ### Credit Reported upstream to KnpLabs/snappy ([GHSA-c5fp-p67m-gq56](https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56)); identified as applicable to `pontedilana/php-weasyprint`, which mirrors the same code.

CVE-2026-49359 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-49359?
CVE-2026-49359 is a security vulnerability in Pontedilana/php weasyprint involving PhpWeasyPrint vulnerable to SSRF and local file disclosure via the attachment option under CWE-918: Server-Side Request Forgery (SSRF).
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-49359?
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-49359?
CVE-2026-49359 has a CVSS v3.1 base score of 6.5 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N.
What CWE is associated with CVE-2026-49359?
CVE-2026-49359 is classified under CWE-918: Server-Side Request Forgery (SSRF) (The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.).
How can I check Packagist dependencies for CVE-2026-49359?
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-x8g9-h984-pc36",
  "modified" : "2026-06-26T22:11:40Z",
  "published" : "2026-06-26T22:11:40Z",
  "aliases" : [ "CVE-2026-49359" ],
  "summary" : "PhpWeasyPrint vulnerable to SSRF and local file disclosure via the attachment option",
  "details" : "### Summary\n\n`pontedilana/php-weasyprint` fetches the content of option values server-side via `file_get_contents()` when the value looks like a URL, without restricting the URL scheme. The `attachment` option of `Pdf` is the reachable sink: any value that passes `isOptionUrl()` (`filter_var(..., FILTER_VALIDATE_URL)`) is downloaded by the PHP process and embedded into the generated PDF. Because `FILTER_VALIDATE_URL` accepts `http`, `https`, `ftp`, `file` and PHP stream wrappers such as `php://`, an attacker who can influence the `attachment` value reaches both a **Server-Side Request Forgery** primitive (e.g. internal HTTP endpoints, cloud metadata) and a **local file disclosure** primitive (`file://`, `php://filter/...`), with the fetched bytes exfiltrated as a PDF attachment.\n\nThis is the same class of issue KnpLabs/snappy patched for its `xsl-style-sheet` option in [GHSA-c5fp-p67m-gq56](https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56). The library is documented as a one-to-one substitute for KnpLabs/snappy and shares the same code shape.\n\n### Affected versions\n\n`pontedilana/php-weasyprint` versions `<= 2.5.1`.\n\nPatched in: `2.6.0`.\n\n### Privilege required\n\nAny caller that can influence the `attachment` option value handed to `Pdf::generate()` / `Pdf::getOutput()` / `setOption('attachment', ...)`. Typical reach paths: a value sourced from a request parameter, a per-tenant configuration row, or any user-controllable field that flows into the attachment list.\n\n### Vulnerable code\n\n`src/Pdf.php` — `isOptionUrl()` accepts any well-formed URL regardless of scheme:\n\n```php\nprotected function isOptionUrl($option): bool\n{\n    return false !== \\filter_var($option, \\FILTER_VALIDATE_URL);\n}\n```\n\n`src/Pdf.php` — `handleArrayOptions()` fetches the URL content for the `attachment` option:\n\n```php\n$fetchUrlContent = 'attachment' === $option && $this->isOptionUrl($item);\nif ($saveToTempFile || $fetchUrlContent) {\n    $fileContent = $fetchUrlContent ? \\file_get_contents($item) : $item;\n    $returnOptions[] = $this->createTemporaryFile($fileContent, $this->optionsWithContentCheck[$option] ?? 'temp');\n}\n```\n\n`FILTER_VALIDATE_URL` returns truthy for `http://`, `https://`, `ftp://`, `file://localhost/...`, and `php://filter/...`, so `\\file_get_contents()` is invoked on attacker-chosen schemes with no allow-list.\n\n### Proof of concept\n\n```php\n<?php\nuse Pontedilana\\PhpWeasyPrint\\Pdf;\n\n$pdf = new Pdf('/usr/local/bin/weasyprint');\n\n// Attacker-controlled attachment value (e.g. from a request / tenant config):\n//   SSRF:               http://169.254.169.254/latest/meta-data/iam/security-credentials/\n//   Local file read:    php://filter/convert.base64-encode/resource=/etc/passwd\n$attachment = $_GET['doc'];\n\n$pdf->generate('page.html', 'out.pdf', [\n    'attachment' => $attachment,\n]);\n\n// The bytes fetched server-side by file_get_contents() are embedded in out.pdf,\n// allowing the attacker to read internal HTTP responses or local files.\n```\n\n### Impact\n\n- **SSRF**: the server fetches arbitrary `http(s)`/`ftp` URLs, reaching internal-only services, link-local metadata endpoints, etc.\n- **Local file / wrapper disclosure**: `php://filter/...` (and similar) let an attacker read and exfiltrate local file content inside the generated PDF.\n- Affects any consumer that does not fully control the `attachment` option value.\n\nNote: passing a plain local path (e.g. `/etc/passwd`) or a `file://` path that resolves to an existing file is handled as a normal local attachment and is **not** the issue addressed here — that is the documented local-attachment feature (callers must not pass untrusted input to the option). The fix specifically removes the server-side fetch amplification through non-`http(s)` schemes.\n\nCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (6.5, Medium) — adjust `PR`/`S`/`A` to the consuming application's reachability (e.g. `PR:N` if the attachment value is reachable from an unauthenticated surface).\n\nCWE-918 (Server-Side Request Forgery); secondary CWE-22 (Improper Limitation of a Pathname) for the wrapper-based file read.\n\n### Suggested fix\n\nRestrict the schemes the library will fetch to an allow-list (`http`, `https` by default), and treat any other scheme as inline content instead of fetching it:\n\n```php\nprivate array $allowedSchemes = ['http', 'https'];\n\n// new optional 4th constructor argument: ?array $allowedSchemes = null\n\nprotected function isOptionUrl($option): bool\n{\n    $url = \\parse_url((string)$option);\n\n    return false !== $url\n        && isset($url['scheme'])\n        && \\in_array(\\strtolower($url['scheme']), $this->allowedSchemes, true);\n}\n```\n\nA value with a non-allowed scheme (`file://`, `php://`, `ftp://`, ...) is then never passed to `file_get_contents()`.\n\n### Credit\n\nReported upstream to KnpLabs/snappy ([GHSA-c5fp-p67m-gq56](https://github.com/KnpLabs/snappy/security/advisories/GHSA-c5fp-p67m-gq56)); identified as applicable to `pontedilana/php-weasyprint`, which mirrors the same code.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"
  } ],
  "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-c5fp-p67m-gq56"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pontedilana/php-weasyprint/security/advisories/GHSA-x8g9-h984-pc36"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-49359"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pontedilana/php-weasyprint/commit/9582dcf119a405276cf55e9e10bc577a887792cb"
  }, {
    "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-918" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-26T22:11:40Z",
    "nvd_published_at" : "2026-06-19T18:16:19Z"
  }
}