Skip to content

Validate translate-from-URL fetches against SSRF (fixes #1188) - #1189

Open
carfeii wants to merge 1 commit into
PDFMathTranslate:mainfrom
carfeii:fix/translate-from-url-ssrf
Open

carfeii wants to merge 1 commit into
PDFMathTranslate:mainfrom
carfeii:fix/translate-from-url-ssrf

Conversation

@carfeii

@carfeii carfeii commented Sep 11, 2026

Copy link
Copy Markdown

Fixes #1188.

Problem

download_with_limit (pdf2zh/gui.py) and translate() (pdf2zh/high_level.py) fetch caller-supplied URLs server-side with no scheme/address validation, so a user can make the server request loopback, private-range, or link-local (cloud metadata) addresses and other internal services. high_level also follows redirects, so a public URL can bounce to an internal one. PDF responses are translated and returned to the caller.

Change

  • Add assert_public_http_url(url) in high_level.py: require an http/https scheme and that every address the host resolves to is globally routable (rejects loopback, private, link-local, reserved, and IPv4-mapped forms).
  • Add fetch_public_url(url, **kwargs): disables automatic redirects and re-validates each hop before following it.
  • high_level.translate now uses fetch_public_url; gui.download_with_limit calls assert_public_http_url and follows redirects with the same re-validating loop.

Python's ipaddress already treats NAT64/6to4 transition forms as non-global, so no extra unwrapping is needed. Legitimate public PDF links (including ones that redirect) keep working.

download_with_limit (gui.py) and translate() (high_level.py) fetched
caller-supplied URLs server-side with no scheme or address validation, so
a user could make the server request loopback, private-range, or
link-local (cloud metadata) addresses and other internal services; the
core path also followed redirects. When the target returned a PDF its
content was returned to the caller.

Add assert_public_http_url (require http/https and a globally-routable
resolved address) and fetch_public_url (redirects re-validated per hop) in
high_level.py, and apply both to the two URL-fetch sinks.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSRF: translate-from-URL fetches arbitrary internal addresses (gui download_with_limit + high_level.translate)

1 participant