Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-49452

CVE-2026-49452: WeasyPrint SSRF Vulnerability

CVE-2026-49452 is an SSRF flaw in WeasyPrint that allows CSS injection through unescaped HTML attributes, enabling server-side requests. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-49452 Overview

CVE-2026-49452 is a CSS injection vulnerability in WeasyPrint, a Python library that converts HTML documents into PDF files. Versions prior to 69.0 embed unescaped HTML presentational-hint attribute values into generated CSS when presentational_hints=True. The background attribute is inserted into a background-image:url() declaration and parsed by tinycss2.parse_blocks_contents(), allowing attacker-controlled HTML to inject arbitrary CSS declarations. Applications that render untrusted HTML with presentational hints enabled are exposed to CSS injection and server-side request forgery through injected url() values. The issue is tracked as [CWE-74] (Improper Neutralization of Special Elements in Output) and is fixed in version 69.0.

Critical Impact

Untrusted HTML input can inject CSS declarations and trigger server-side requests through crafted url() values, exposing internal network resources.

Affected Products

  • WeasyPrint versions prior to 69.0
  • Applications rendering untrusted HTML with presentational_hints=True
  • Downstream Python packages and services embedding WeasyPrint for PDF generation

Discovery Timeline

  • 2026-08-18 - CVE-2026-49452 published to NVD
  • 2026-08-19 - Last updated in NVD database

Technical Details for CVE-2026-49452

Vulnerability Analysis

WeasyPrint supports HTML presentational hints, which convert legacy HTML attributes such as background, bgcolor, and width into equivalent CSS declarations. The library performs this translation in weasyprint/css/__init__.py by concatenating attribute values directly into a CSS string. The concatenated text is then handed to tinycss2.parse_blocks_contents() for parsing.

Because the attribute value is not escaped, an attacker who controls the HTML input can close the url() construct and append additional CSS declarations. Injected declarations execute in the styling context of the rendered document. Injected url() values also cause WeasyPrint to issue outbound HTTP requests from the server running the conversion.

Root Cause

The root cause is unsafe string interpolation of untrusted attribute values into a CSS declaration. The background attribute value is inserted into background-image:url(...) without CSS-context escaping or URL validation. Presentational hints share the same parsing pipeline as author stylesheets, so any injected tokens are treated as legitimate CSS.

Attack Vector

An attacker submits HTML containing an element such as <body background="..."> where the attribute value contains characters that terminate the url() function and introduce new CSS blocks. When the target application calls WeasyPrint with presentational_hints=True, the injected CSS is parsed and applied. The attacker can point url() at internal endpoints to perform blind server-side request forgery, or manipulate the rendered PDF's styling to alter document content.

python
# Patch excerpt from weasyprint/formatting_structure/boxes.py
# The fix replaces the loose parse_html_integer with parse_integer
# and routes presentational hints through HTML-aware parsers.

if self.children:
    return len(self.children)
else:
-   from ..html import parse_html_integer
+   from ..html import parse_integer

-   span = parse_html_integer(self.element.get('span'))
+   span = parse_integer(self.element.get('span'))
    return max(span, 1) if span is not None else 1

Source: GitHub Commit e158264

Detection Methods for CVE-2026-49452

Indicators of Compromise

  • Outbound HTTP requests from PDF-generation workers to unexpected internal or external hosts during rendering
  • HTML input containing background, bgcolor, or similar legacy attributes with parentheses, semicolons, or CSS keywords
  • WeasyPrint logs showing fetch attempts for URLs that did not appear in the source document body

Detection Strategies

  • Inspect application dependencies for WeasyPrint versions below 69.0 using pip show weasyprint or SBOM tooling
  • Review code paths that invoke HTML(...).write_pdf(presentational_hints=True) on user-supplied HTML
  • Instrument the PDF-generation service with egress monitoring to detect unauthorized outbound requests

Monitoring Recommendations

  • Log and alert on DNS resolutions and HTTP requests originating from PDF-rendering hosts
  • Monitor for repeated conversion errors from tinycss2 that may indicate injection attempts
  • Correlate PDF-generation activity with identity and network telemetry in your SIEM to spot anomalous fetch patterns

How to Mitigate CVE-2026-49452

Immediate Actions Required

  • Upgrade WeasyPrint to version 69.0 or later in all environments that process untrusted HTML
  • Audit application code and disable presentational_hints on untrusted input until the upgrade is complete
  • Restrict egress from PDF-rendering workers to only the destinations required for legitimate operation

Patch Information

The fix landed in WeasyPrint 69.0 via the pull request that routes presentational hints through HTML-aware parsers rather than raw string concatenation. See the GitHub Security Advisory GHSA-jhhc-3hcp-qhm5, the GitHub Pull Request Discussion, and the GitHub Release Notes v69.0 for full details.

Workarounds

  • Set presentational_hints=False (the default) when invoking WeasyPrint on untrusted HTML
  • Sanitize input HTML to strip legacy presentational attributes such as background, bgcolor, width, and height before rendering
  • Place PDF-generation workers on an isolated network segment with strict egress allow-listing to prevent server-side request forgery
bash
# Upgrade WeasyPrint to a patched release
pip install --upgrade 'weasyprint>=69.0'

# Verify the installed version
python -c "import weasyprint; print(weasyprint.__version__)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.