CVE-2026-49260 Overview
CVE-2026-49260 is a shell command injection vulnerability in pontedilana/php-weasyprint, a PHP library that generates PDFs from URLs or HTML. The flaw exists in versions prior to 2.5.1. The library's buildCommand routine wraps the binary path with escapeshellarg() and then validates the quoted result with is_executable(). The validation check never matches a real file, leaving the unescaped $binary value to flow directly into Symfony\Component\Process\Process::fromShellCommandline(). Any deployment that sources the binary path from configuration, environment variables, or per-tenant settings reaches a shell command injection sink [CWE-78].
Critical Impact
Attackers who control the WeasyPrint binary path can execute arbitrary shell commands with the privileges of the PHP process.
Affected Products
- pontedilana/php-weasyprint versions prior to 2.5.1
- PHP applications loading the binary path from configuration or environment variables
- Multi-tenant deployments allowing per-tenant binary path overrides
Discovery Timeline
- 2026-06-19 - CVE-2026-49260 published to NVD
- 2026-06-22 - Last updated in NVD database
Technical Details for CVE-2026-49260
Vulnerability Analysis
The buildCommand method in src/AbstractGenerator.php and src/Pdf.php constructs the shell command used to invoke WeasyPrint. The original logic called escapeshellarg($binary) and then evaluated is_executable() against the quoted string. On POSIX systems, escapeshellarg('/usr/local/bin/weasyprint') returns '/usr/local/bin/weasyprint' with literal single quotes as part of the filename. No such file exists on disk, so is_executable() always returns false. The fallback branch passes the raw $binary value to Process::fromShellCommandline(), where shell metacharacters are interpreted.
PhpWeasyPrint is documented as a one-to-one substitute for KnpLabs/snappy and inherited the identical pre-fix code path that KnpLabs patched in GHSA-vpr4-p6fq-85jc.
Root Cause
The validation guard relies on is_executable() operating on a quoted string. Single-quote characters are part of the argument passed to the function, so the existence check fails universally. The conditional collapses to its unsafe branch on every invocation, defeating the intended escaping.
Attack Vector
An attacker who can influence the $binary value via the constructor or setBinary() can inject shell metacharacters. Sources include configuration files, environment variables, database-backed settings, and per-tenant configuration. The injected payload executes through fromShellCommandline() with the privileges of the PHP runtime.
// Vulnerable code in src/AbstractGenerator.php and src/Pdf.php
protected function buildCommand(string $binary, string $input, string $output, array $options = []): string
{
- $escapedBinary = \escapeshellarg($binary);
- $command = \is_executable($escapedBinary) ? $escapedBinary : $binary;
+ $command = $this->getEscapedBinary($binary);
foreach ($options as $key => $option) {
if (null === $option || false === $option) {
Source: pontedilana/php-weasyprint commit 9e86a2b
Detection Methods for CVE-2026-49260
Indicators of Compromise
- Unexpected child processes spawned by PHP-FPM or the web server user, such as /bin/sh -c invocations not originating from legitimate PDF generation.
- WeasyPrint binary path values in configuration that contain shell metacharacters like ;, &&, |, or backticks.
- Outbound network connections initiated by the PHP process to unfamiliar hosts immediately following PDF generation requests.
Detection Strategies
- Inventory all applications using pontedilana/php-weasyprint and identify versions below 2.5.1 via composer.lock audits.
- Review code paths where setBinary() or the generator constructor receives input from environment variables, databases, or tenant configuration.
- Add static analysis rules flagging untrusted input flowing into Process::fromShellCommandline().
Monitoring Recommendations
- Monitor process trees for shell invocations descending from the PHP runtime user.
- Alert on writes to configuration files that store the WeasyPrint binary path.
- Log and review all changes to per-tenant settings that influence external binary execution.
How to Mitigate CVE-2026-49260
Immediate Actions Required
- Upgrade pontedilana/php-weasyprint to version 2.5.1 or later using composer update pontedilana/php-weasyprint.
- Audit all sources that supply the binary path and remove any user-influenced inputs.
- Restrict file system and environment variable write access for the web server account.
Patch Information
Version 2.5.1 replaces the broken escapeshellarg() plus is_executable() check with a dedicated getEscapedBinary() helper. Details are available in the release notes for 2.5.1 and the security advisory GHSA-f5gc-qxf8-mh9g.
Workarounds
- Hardcode the WeasyPrint binary path as a constant inside application code rather than reading it from external sources.
- Validate any externally sourced binary path against an allowlist of absolute file system paths before passing it to the generator.
- Run the PHP process under a restricted user with no shell access and apply mandatory access controls such as AppArmor or SELinux.
# Pin the fixed version in composer.json
composer require pontedilana/php-weasyprint:^2.5.1
composer update pontedilana/php-weasyprint
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

