Oct 7, 2026·8 min read·1 visit
WeasyPrint prior to 70.0 allows unauthenticated remote code execution via malicious EPS images if Ghostscript is installed on the hosting server.
A critical remote code execution vulnerability was identified in WeasyPrint prior to version 70.0. When compiling HTML containing a malicious Encapsulated PostScript (EPS) graphic on a host with Ghostscript installed, Pillow invokes Ghostscript to process the image, executing arbitrary PostScript commands.
WeasyPrint is a widely deployed pythonic document generation library designed to compile structured HTML documents and CSS stylesheets into print-ready PDF files. Web developers frequently integrate this component within backend architectures to dynamically generate user-facing assets such as financial invoices, corporate statements, medical records, and custom resumes. Due to the nature of document compilation, WeasyPrint exposes a significant network attack surface, as it must fetch and render external multi-media assets, including vector and raster images, over the network or from internal directories.
During a comprehensive, NLNet foundation-funded security audit executed by Radically Open Security researcher Stefan Vink, a critical validation flaw was identified in WeasyPrint's image processing component. The vulnerability, tracked as CVE-2026-106443, resides in the way WeasyPrint's fetching module processes external files. Instead of validating incoming media assets against a strict list of safe MIME types, WeasyPrint forwards raw, unvalidated byte arrays directly to Pillow's (PIL) generic file loader, enabling an attacker to dispatch malicious files to hazardous backend parsers.
When WeasyPrint processes an input HTML document containing a malicious Encapsulated PostScript (EPS) file, the Pillow library automatically matches the magic bytes of the file and invokes its internal EPS renderer. If the underlying host environment contains an active installation of Ghostscript, Pillow attempts to rasterize the vector file by spawning an external Ghostscript subprocess. Because PostScript is a Turing-complete language, an attacker who successfully routes execution to this interpreter can run arbitrary operations. If the interpreter has known sandbox escape vulnerabilities, this design flaw results in unauthenticated remote code execution on the hosting infrastructure.
The root cause of this vulnerability lies in the architecture of the Pillow image parsing library combined with the lack of input sanitization in WeasyPrint's asset fetching pipeline. In standard operations, Pillow relies on an automatic format detection mechanism implemented inside Image.open(). When an application passes a file-like object or a byte stream to this function, Pillow reads the initial bytes of the payload to identify file signatures, matching them against registered image plugin classes. When an EPS or PS file is supplied, Pillow matches the signature and instantiates PIL.EpsImagePlugin without querying the calling application for authorization.
Because Pillow cannot natively render the complex vector mathematics of PostScript files, it relies on an external rendering engine. The EpsImagePlugin class contains logic that automatically identifies the path to the system's Ghostscript binary (gs) and launches it as an external subprocess using Python's subprocess API. The target PostScript code is passed directly to the interpreter as an argument or standard input stream. This creates an implicit, invisible bridge from a seemingly passive image loading function to a command-line interpreter execution path.
PostScript is not merely a markup syntax; it is a full, Turing-complete language capable of file-system interactions, mathematical evaluations, and execution flow controls. Ghostscript uses sandboxing parameters, specifically the -dSAFER execution flag, to restrict file modifications and operating system calls during rasterization. However, Ghostscript is notoriously complex, and security researchers have historically bypassed this sandbox through numerous memory corruption and logical evaluation flaws, such as CVE-2024-29510. Consequently, by passing user-supplied EPS bytes to Pillow, WeasyPrint exposes the underlying server to any active or zero-day Ghostscript sandbox escape vectors present in the environment.
To understand the exact mechanics of the vulnerability and the subsequent fix, we analyze the implementation within WeasyPrint's core image handling module, located at weasyprint/images.py. Before the patch was applied in version 70.0, WeasyPrint imported standard components from Pillow without overriding default behavior, allowing Pillow to execute system binaries dynamically when an EPS image signature was parsed.
Below is the representation of the vulnerable code path inside weasyprint/images.py contrasted with the applied security patch:
# === VULNERABLE CODE PATH (Pre-v70.0) ===
from PIL import Image, ImageFile, ImageOps
# The module initialized generic Pillow parameters but did not restrict
# underlying binary execution configurations.
ImageFile.LOAD_TRUNCATED_IMAGES = True
# When an image URI was processed, it was handed straight to Pillow's loader
# which automatically selected EpsImagePlugin if EPS signatures matched:
pillow_image = Image.open(bytestring)# === PATCHED CODE PATH (v70.0) ===
from PIL import EpsImagePlugin, Image, ImageFile, ImageOps
# Don't crash when converting truncated images
ImageFile.LOAD_TRUNCATED_IMAGES = True
# [SECURITY FIX] Don't use Ghostscript to render possibly dangerous EPS files.
# By overriding this variable to False, we prevent EpsImagePlugin from
# identifying or executing the external Ghostscript subprocess.
EpsImagePlugin.gs_binary = FalseBy setting EpsImagePlugin.gs_binary = False globally during module initialization, WeasyPrint completely eliminates the capability of the Pillow library to invoke the external gs command-line utility. If an EPS file is processed, the Pillow library immediately fails to initialize the rendering pipeline and raises an exception. The patch wraps the RasterImage instantiation in a robust exception handling block to prevent these execution failures from crashing the document generation engine, converting the fatal exception into a handled log message instead.
This remediation is highly robust and structurally complete. Since the EpsImagePlugin requires a valid path to gs_binary to generate any subprocess, hardcoding this configuration value to False prevents the subprocess execution path from being reached under any circumstances. It removes the capability entirely, leaving no residual attack paths for variant exploitation of the Ghostscript interpreter via this module.
Exploitation of CVE-2026-106443 requires that the target hosting server has Ghostscript installed and that the application leverages a vulnerable version of WeasyPrint to process user-supplied markup. The attack begins with the generation of an Encapsulated PostScript (EPS) file containing malicious instructions. Since PostScript supports administrative file access operations, an attacker can construct an EPS file that reads or writes local configuration files, or executes administrative utilities on the machine, as demonstrated in the following payload structure:
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 100 100
(/tmp/test-marker.txt) (w) file
dup (test_GHOSTSCRIPT_MARKER\n) writestring
closefile
0.5 setgray 0 0 100 100 rectfill
showpage
%%EOFOnce the payload is formulated, the adversary must force WeasyPrint to fetch and process it. This can be achieved through multiple injection vectors within the submitted HTML. The most direct vector is an <img> tag pointing to the malicious resource. If the target application implements network controls to prevent fetching remote resources, the attacker can bypass this restriction entirely by encoding the payload as a base64 string inside an inline data URI directly in the HTML or CSS stylesheet:
<img src="data:image/eps;base64,JVBTLUFkb2JlLTMuMCBFUFNGLTMuMAolJUJvdW5kaW5nQm94OiAwIDAgMTAwIDEwMAooL3RtcC90ZXN0LW1hcmtlci50eHQpICh3KSBmaWxlCmR1cCAodGVzdF9HSE9TVFNDUklQVF9NQVJLRVJcbikgd3JpdGVzdHJpbmcKY2xvc2VmaWxlCjAuNSBzZXRncmF5IDAgMCAxMDAgMTAwIHJlY3RmaWxsCnNob3dwYWdlCiUlRU9GCg==">When the backend server triggers the PDF compilation process, WeasyPrint extracts the image asset, routes it to Pillow, and invokes the Ghostscript interpreter. If Ghostscript is vulnerable to a sandbox escape (e.g., CVE-2024-29510), the execution limits are ignored, and the commands are executed directly in the context of the running web application server.
The impact of this vulnerability is critical, representing a direct path to unauthenticated remote code execution on affected application servers. The CVSS 3.1 score is evaluated at 8.8 (High Severity), reflecting the critical combination of a low attack complexity and the complete absence of required user interaction. The attack vector is Network (AV:N), meaning the vulnerability can be exploited remotely across public boundaries without requiring local access to the hosting network.
Upon successful exploitation of the Ghostscript interpreter, the security posture of the application is completely compromised. Since the commands are run under the context of the application server user (e.g., www-data or gunicorn), the attacker gains the ability to read sensitive environmental variables, extract database credentials, manipulate local application source files, or pivot to local container endpoints. In multi-tenant environments, this can lead to cross-tenant data exposure and horizontal privilege escalation.
Currently, the EPSS score for this vulnerability remains low (0.00689, representing the 51.27th percentile), as active exploitation has not yet been widely observed in the wild. Additionally, the vulnerability is not currently listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, because PDF generation engines are commonly exposed to public inputs and often run with elevated privileges in internal networks, the actual risk profile for enterprise deployments is substantial.
The primary and most effective remediation path is to upgrade WeasyPrint to version 70.0 or later immediately. This version includes the hardcoded mitigation that disables Pillow's command execution path. In addition to upgrading the Python library, security teams should implement defensive system hardening practices to protect application hosts.
If upgrading WeasyPrint immediately is not possible due to legacy system dependencies, administrators can deploy a programmatic workaround. By modifying the application's entrypoint script (such as wsgi.py, asgi.py, or manage.py) to globally disable Ghostscript parsing inside Pillow prior to initializing any other libraries, you can effectively neutralize the attack surface:
# Programmatic hotfix for legacy WeasyPrint installations
from PIL import EpsImagePlugin
EpsImagePlugin.gs_binary = FalseAdditionally, host environments should be audited to ensure that Ghostscript is uninstalled if it is not explicitly required for business operations. Containerized workloads (e.g., Docker) should use slim or minimal base images that exclude heavy command-line utilities like Ghostscript. Finally, egress traffic filtering should be enforced on PDF rendering hosts to prevent the application from making unvalidated outbound connections to retrieve malicious EPS files from the public internet.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
WeasyPrint Kozea | < 70.0 | 70.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-20 |
| Attack Vector | Network (AV:N/AC:L/PR:L/UI:N) |
| CVSS Severity Score | 8.8 |
| EPSS Score | 0.00689 (51.27th Percentile) |
| Exploit Status | PoC Available |
| CISA KEV Status | Not Listed |
The product receives input that is expected to be safe but is processed without validating the structure or content.
An authorization bypass vulnerability in the Spotify Backstage TechDocs backend plugin allows authenticated attackers with access to at least one valid TechDocs site to read arbitrary static documentation from other entities. This occurs due to un-sanitized relative subpaths passing directly to external storage drivers.
The @backstage/plugin-scaffolder-backend package prior to version 4.1.0 is vulnerable to sensitive information exposure in Scaffolder task failure events. Under specific template and failure conditions, an authenticated user can retrieve backend-managed credentials, such as VCS access tokens and API keys, from affected task execution events and stored database logs. This vulnerability has been remediated in version 4.1.0 of the package and is bundled with the Backstage platform release v1.54.6.
A critical security flaw exists in PraisonAI before version 4.6.78 when operating in AgentMail webhook mode. The application processes incoming POST requests without checking for cryptographic signatures, allowing unauthenticated attackers to forge emails, spoof identities, and force AI agents to execute unauthorized operations.
A missing authorization vulnerability (CWE-862) exists in praisonai-platform versions prior to 0.1.9, allowing low-privileged workspace members to delete planning dependencies on issues owned by administrators by routing the deletion request through an attacker-owned issue.
CVE-2026-46438 is a critical Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability identified in the wger fitness manager prior to version 2.6. An authenticated attacker can exploit a missing authorization check on the slot_entry API parameter to inject unauthorized workout logs into another user's training schedule. This results in the corruption of the target user's automated progressive-overload calculations.
CVE-2026-105795 (GHSA-6gw6-rv2g-25mg) is a critical path traversal vulnerability in Microsoft Kiota, an OpenAPI-based HTTP client and plugin manifest generator. In affected versions (1.25.1 to < 1.35.0), Kiota propagates the unvalidated `x-ai-capabilities.response_semantics.oauth_card_path` vendor extension directly into generated API plugin manifests, leading to potential path traversal exploitation by downstream consumers.