A Server-Side Request Forgery (SSRF) Protection Bypass exists in WeasyPrint's default_url_fetcher. The vulnerability allows attackers to access internal network resources (such as localhost services or cloud metadata endpoints) even when a developer has implemented a custom url_fetcher to block such access. This occurs because the underlying urllib library follows HTTP redirects automatically without re-validating the new destination against the developer's security policy.
The default URL fetching mechanism in WeasyPrint (default_url_fetcher in weasyprint/urls.py) is vulnerable to a Server-Side Request Forgery (SSRF) Protection Bypass.
While WeasyPrint allows developers to define custom url_fetcher functions to validate or sanitize URLs before fetching (e.g., blocking internal IP addresses or specific ports), the underlying implementation uses Python's standard urllib.request.urlopen. By default, urllib automatically follows HTTP redirects (status codes 301, 302, 307, etc.) without returning control to the developer's validation logic for the new target URL.
This behavior creates a Time-of-Check to Time-of-Use (TOCTOU) vulnerability. An attacker can provide a URL that passes the developer's allowlist/blocklist (the Check) but immediately redirects to a blocked internal resource (the Use).
To reproduce this vulnerability, use the following setup. This scenario simulates a developer attempting to blacklist access to internal hostnames (e.g., localhost).
1. victim.py (Internal Service - Port 5000) Simulates a sensitive internal service running on localhost.
from flask import Flask
app = Flask(__name__)
@app.route('/secret')
def secret():
return "CRITICAL_INTERNAL_DATA"
if __name__ == '__main__':
# Listens on localhost:5000
app.run(port=5000)
2. attacker.py (External Redirector - Port 1337) Simulates an external server. It accepts a request and redirects it to the blocked...
68.0Exploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:HI:NA:N7.5/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N