# datamodel-code-generator vulnerable to SSRF via JSON-Schema `$ref` to HTTP URL (silent by default)

datamodel-code-generator silently dereferences HTTP(S) $ref in JSON-Schema/OpenAPI docs, letting a schema author pivot to internal hosts and leak responses into generated Python.

- Payout: Research
- Severity: high
- Program: datamodel-code-generator
- Found by: thegr1ffyn
- Disclosed: 2026-07-28
- CVE: CVE-2026-54690
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-954p-556p-r752
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-954p-556p-r752
- Tags: area:oss domain:oss impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:python technique:source-review vuln:info-disclosure vuln:ssrf

**Target:** JSON-Schema/OpenAPI $ref resolver in datamodel-codegen CLI
**Root cause:** `_get_ref_body` only blocks remote refs when `allow_remote_refs is False`; the default `None` merely warns and falls through to `_get_ref_body_from_url`, which fetches with no IP/host validation and follows redirects unconditionally.
**Steps:**
1. Install `pip install 'datamodel-code-generator[http]'` (affected 0.9.1–0.60.2).
2. Craft a JSON-Schema/OpenAPI doc with a `$ref` pointing at an internal URL, e.g. `http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>`.
3. Run `datamodel-codegen` on the document without `--allow-remote-refs=false`.
4. Observe deprecation warning emitted, then the URL is fetched anyway.
5. Inspect generated `.py` — remote body reflected verbatim via `description`/`title`/`properties`.
**How found:** Code review of `_get_ref_body` in `parser/jsonschema.py` revealed the `allow_remote_refs is None` branch only warns and falls through to the fetch sink, unlike the explicit `False` branch that raises.
**Exploitation:** Attacker controls a schema document consumed by the victim (trojaned public OpenAPI spec, customer-uploaded schema in B2B SaaS, or PR-added schema in CI). The `$ref` URL is fetched from the victim's network context; the response is parsed as a sub-schema and merged into the model graph, so its contents appear in the generated Python handed back to the attacker or leaked in CI artifacts.
**Escalation:** Chaining to cloud metadata (169.254.169.254) yields IAM credentials; internal admin endpoints yield user lists; CI VPC-only services leak into PR artifacts.
**Insight:** When a security gate is added as a deprecation-compat default (tri-state None/True/False), check whether the None branch actually blocks or just warns — the fall-through is the bug. Also check whether the *document author* (not the CLI user) controls the URL, which raises severity.

