datamodel-code-generator's built-in HTTP fetcher (http.get_body) issues an httpx.GET against any URL passed to --url (or reached via a redirect chain) with no allow-list, no deny-list, no IP/host validation, and follow_redirects=True. Loopback addresses, RFC1918 ranges, link-local (169.254.169.254 cloud metadata), unique-local IPv6 and any other network-accessible target are all reachable. The JSON/YAML response body is parsed as a schema and reflected into the generated .py source, exfiltrating the response to anyone with access to that file (commonly committed to a repository).
Sink: src/datamodel_code_generator/http.py, get_body (lines 31–61, at tag 0.60.1 / commit a321547e):
def get_body(url, headers=None, ignore_tls=False,
query_parameters=None, timeout=DEFAULT_HTTP_TIMEOUT) -> str:
httpx = _get_httpx()
try:
response = httpx.get(
url,
headers=headers,
verify=not ignore_tls,
follow_redirects=True, # (A)
params=query_parameters,
timeout=timeout,
)
except Exception as e:
...
if response.status_code >= 400:
...
content_type = response.headers.get("content-type", "").lower()
if "text/html" in content_type:
raise SchemaFetchError(...) # (B) — only filter
return response.text # (C) → embedded in generated.py
text/html. Non-HTML internal endpoints (JSON APIs, cloud metadata, admin services) pass through.title, description, properties, etc. land in the generated .py as class attributes and Field(description=...) strings.get_body is called by parser/base.py:1326 (_get_text_from_url), which is reached from CLI argument...
0.61.0Exploitability
AV:NAC:LPR:NUI:RScope
S:CImpact
C:HI:LA:N8.2/CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:NInput Validation