chore(deps): update dependency weasyprint to v70 [security] #16
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "renovate/pypi-weasyprint-vulnerability"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This PR contains the following updates:
69.0→70.0weasyprint Has Server-Side Request Forgery (SSRF)
CVE-2026-55073 / GHSA-jf6q-chmf-3h3v / PYSEC-2026-3940
More information
Details
Summary
url_fetcheris WeasyPrint's documented mechanism for restricting resource loading - applications use it to blockfile://, internal hosts, etc. when rendering untrusted input.Two
write_pdf()channels ignore the document'surl_fetcherand build a fresh defaultURLFetcher()instead. A restrictive fetcher set onHTML()is silently bypassed for:xmp_metadata=[url]- the URL is fetched and the bytes are embedded verbatim in the output PDF. This is an arbitrary local file read when the path is attacker-influenced.stylesheets=[url_or_path]- the sheet is fetched and applied. This is SSRF / arbitrary local-or-internal resource loading, and it is transitive: the permissive fetcher propagates through the whole@import/url()graph.Applications affected are those that (1) run WeasyPrint server-side, (2) set a restrictive
url_fetcherto blockfile://or internal hosts, and (3) forward an attacker-influenced URL/path into either parameter - e.g. PDF rendering APIs, invoice/report generators, document SaaS.Affected versions
All versions through current
main- v69.0, commit2945986160dedd97a7547be03805b667964e422a.Root cause
select_source()defaults to a fresh fetcher when none is passed (weasyprint/urls.py):Five of the seven resource-loading sites thread the document's fetcher correctly:
<link rel=stylesheet>inweasyprint/css/__init__.py<style>inweasyprint/css/__init__.py@importinweasyprint/css/__init__.py@font-face/local()inweasyprint/text/fonts.py@color-profile srcinweasyprint/css/__init__.py<img>, CSSurl(), SVG) inweasyprint/images.pyTwo do not — they build a fresh default fetcher instead:
write_pdf(xmp_metadata=[...])inweasyprint/pdf/__init__.pywrite_pdf(stylesheets=[str])inweasyprint/document.pyxmp_metadata-pdf/__init__.pycallsselect_source(url)with nourl_fetcher, so the default fetcher runs regardless of what the caller configured:stylesheets-document.pybuilds each sheet without passingurl_fetcher, andCSS.__init__then defaults to a freshURLFetcher():Because
@import/url()inherit a CSS object's fetcher, the permissive fetcher propagates to the entire import graph - so the bypass is transitive.Reproduction
Each script defines a
Blockfetcher that refuses everyfile://, writes its own fixture to a temp dir, and prints a boolean.Truemeans the restrictive fetcher was bypassed. No external files or network needed.1 -
xmp_metadata=reads afile://the fetcher blocks(
pdf_variant='pdf/a-3b'makes the embedded bytes observable in the output; the read happens regardless of variant.)2 -
stylesheets=applies a blockedfile://sheet (with control)3 - the
stylesheets=bypass is transitive4 -
xmp_metadata=discloses a credentials file in fullAn attacker who controls the
xmp_metadatapath reads any file the rendering process can access and receives its contents in the generated PDF.5 - scope of the
stylesheets=channel (honest bound)The sheet is applied, but its content does not leak verbatim - CSS comments are stripped during parsing. So this channel is SSRF / resource application, not verbatim disclosure on its own.
Suggested fix
Route both call sites through the document's
url_fetcher, matching the five sites that already do this.pdf/__init__.py-select_source(url, url_fetcher=self.url_fetcher). (Alternatively, restrictxmp_metadatato byte strings so no URL fetching occurs.)document.py-CSS(guess=css, ..., url_fetcher=html.url_fetcher). This one change also closes the transitive case, since imported sheets inherit the parent's fetcher.Severity
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
weasyprint Has Server-Side Request Forgery (SSRF)
CVE-2026-55073 / GHSA-jf6q-chmf-3h3v / PYSEC-2026-3940
More information
Details
Summary
url_fetcheris WeasyPrint's documented mechanism for restricting resource loading - applications use it to blockfile://, internal hosts, etc. when rendering untrusted input.Two
write_pdf()channels ignore the document'surl_fetcherand build a fresh defaultURLFetcher()instead. A restrictive fetcher set onHTML()is silently bypassed for:xmp_metadata=[url]- the URL is fetched and the bytes are embedded verbatim in the output PDF. This is an arbitrary local file read when the path is attacker-influenced.stylesheets=[url_or_path]- the sheet is fetched and applied. This is SSRF / arbitrary local-or-internal resource loading, and it is transitive: the permissive fetcher propagates through the whole@import/url()graph.Applications affected are those that (1) run WeasyPrint server-side, (2) set a restrictive
url_fetcherto blockfile://or internal hosts, and (3) forward an attacker-influenced URL/path into either parameter - e.g. PDF rendering APIs, invoice/report generators, document SaaS.Affected versions
All versions through current
main- v69.0, commit2945986160dedd97a7547be03805b667964e422a.Root cause
select_source()defaults to a fresh fetcher when none is passed (weasyprint/urls.py):Five of the seven resource-loading sites thread the document's fetcher correctly:
<link rel=stylesheet>inweasyprint/css/__init__.py<style>inweasyprint/css/__init__.py@importinweasyprint/css/__init__.py@font-face/local()inweasyprint/text/fonts.py@color-profile srcinweasyprint/css/__init__.py<img>, CSSurl(), SVG) inweasyprint/images.pyTwo do not — they build a fresh default fetcher instead:
write_pdf(xmp_metadata=[...])inweasyprint/pdf/__init__.pywrite_pdf(stylesheets=[str])inweasyprint/document.pyxmp_metadata-pdf/__init__.pycallsselect_source(url)with nourl_fetcher, so the default fetcher runs regardless of what the caller configured:stylesheets-document.pybuilds each sheet without passingurl_fetcher, andCSS.__init__then defaults to a freshURLFetcher():Because
@import/url()inherit a CSS object's fetcher, the permissive fetcher propagates to the entire import graph - so the bypass is transitive.Reproduction
Each script defines a
Blockfetcher that refuses everyfile://, writes its own fixture to a temp dir, and prints a boolean.Truemeans the restrictive fetcher was bypassed. No external files or network needed.1 -
xmp_metadata=reads afile://the fetcher blocks(
pdf_variant='pdf/a-3b'makes the embedded bytes observable in the output; the read happens regardless of variant.)2 -
stylesheets=applies a blockedfile://sheet (with control)3 - the
stylesheets=bypass is transitive4 -
xmp_metadata=discloses a credentials file in fullAn attacker who controls the
xmp_metadatapath reads any file the rendering process can access and receives its contents in the generated PDF.5 - scope of the
stylesheets=channel (honest bound)The sheet is applied, but its content does not leak verbatim - CSS comments are stripped during parsing. So this channel is SSRF / resource application, not verbatim disclosure on its own.
Suggested fix
Route both call sites through the document's
url_fetcher, matching the five sites that already do this.pdf/__init__.py-select_source(url, url_fetcher=self.url_fetcher). (Alternatively, restrictxmp_metadatato byte strings so no URL fetching occurs.)document.py-CSS(guess=css, ..., url_fetcher=html.url_fetcher). This one change also closes the transitive case, since imported sheets inherit the parent's fetcher.Severity
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).
Release Notes
Kozea/WeasyPrint (weasyprint)
v70.0Compare Source
Read about this release on our blog.
This is a security update (CVE-2026-55073, GHSA-r543-q48m-4c9j).
We strongly recommend to upgrade WeasyPrint to the latest version if you: * embed untrusted images, or * rely on the URL fetcher to filter metadata or stylesheets passed as Python parameters.
Security
Features
Bug fixes
Performance
Documentation
Contributors
Backers and sponsors
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Mend Renovate CLI.