{"id":"CVE-2026-54653","aliases":["GHSA-386q-5hp3-95m9","PYSEC-2026-3555"],"title":"`datamodel-code-generator` vulnerable to code injection in via attacker-controlled `default_factory` schema field","summary":"`datamodel-code-generator` vulnerable to code injection in via attacker-controlled `default_factory` schema field","severity":"high","cvss":8.8,"cvssVector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H","vendor":"datamodel-code-generator","product":"datamodel-code-generator","ecosystem":"pip","affected":["datamodel-code-generator >= 0.17.0, < 0.60.2"],"patched":["datamodel-code-generator 0.60.2"],"published":"2026-07-28","updated":"2026-09-10","sourceUpdated":"2026-09-10T03:51:09.992619034Z","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-386q-5hp3-95m9","references":[{"url":"https://github.com/koxudaxi/datamodel-code-generator/security/advisories/GHSA-386q-5hp3-95m9"},{"url":"https://github.com/koxudaxi/datamodel-code-generator/commit/17fc235e234cbcfaaadef8c74cb72c9687db0d1d"},{"url":"https://github.com/koxudaxi/datamodel-code-generator"},{"url":"https://github.com/koxudaxi/datamodel-code-generator/releases/tag/0.60.2"},{"url":"https://github.com/advisories/GHSA-386q-5hp3-95m9"}],"tags":["osv","pip","ghsa"],"epss":0.00447,"epssPercentile":0.38285,"cwe":["CWE-94","CWE-1336"],"ingestedAt":"2026-07-28T22:40:03.451Z","slug":"CVE-2026-54653","body":"## Overview\n\n### Summary\n\n`datamodel-code-generator` is vulnerable to code injection when generating Python models from an attacker-controlled JSON Schema, OpenAPI, YAML, JSON, Avro, Protobuf, or XSD schema. When a property carries a `\"default_factory\"` key, its value is interpolated verbatim — as a raw Python expression — into the generated `Field(default_factory=...)` / `field(default_factory=...)` call. Because this assignment is evaluated at class-definition time (i.e. on `import` of the generated module), an attacker who controls the schema controls a Python expression that runs in the consumer's process. No special CLI flags are required.\n\n### Details\n\nThe vulnerable chain spans the JSON-Schema-shaped parser and three sink locations (Pydantic v2, dataclass, msgspec):\n\n**Source — schema → `extras`**:\n\n- `src/datamodel_code_generator/parser/jsonschema.py:600-614` — `DEFAULT_FIELD_KEYS` includes the literal string `\"default_factory\"`.\n- `src/datamodel_code_generator/parser/jsonschema.py:457-459` — `JsonSchemaObject.__init__` stores any non-standard key (including `default_factory`) in `self.extras`.\n- `src/datamodel_code_generator/parser/jsonschema.py:797-812` — `get_field_extras` preserves `default_factory` through to the field model.\n\n**Sinks — `extras` → generated Python expression**:\n\n1. `src/datamodel_code_generator/model/pydantic_base.py:222-249`:\n\n   ```python\n   default_factory = data.pop(\"default_factory\", None)\n   ...\n   if default_factory is not None:\n       field_arguments = [f\"default_factory={default_factory}\", *field_arguments]\n   ```\n\n   The `default_factory` value is interpolated raw (no `repr()`, no validation).\n\n2. `src/datamodel_code_generator/model/dataclass.py:211`:\n\n   ```python\n   f\"{k}={v if k == 'default_factory' else repr(v)}\"\n   ```\n\n   Explicit special-case to skip `repr()` for `default_factory`.\n\n3. `src/datamodel_code_generator/model/msgspec.py:361` — same pattern as dataclass.\n\nBecause `default_factory` is in `DEFAULT_FIELD_KEYS`, no special CLI flag is needed to reach the sink. Any input format that uses the JSON-Schema-shaped parser (`jsonschema`, `openapi`, `yaml`, `json`, `dict`, `csv`) — and any input format that converts to it (`avro`, `protobuf`, `xmlschema`) — is in scope.\n\n### Confirmed PoC matrix\n\n| Input file type | Output model type | Result |\n|---|---|---|\n| `jsonschema` | `pydantic_v2.BaseModel` | RCE on import |\n| `jsonschema` | `dataclasses.dataclass` | RCE on import |\n| `jsonschema` | `msgspec.Struct` | RCE on import |\n| `jsonschema` | `typing.TypedDict` | safe (TypedDict doesn't render `field()`; `default_factory` silently dropped) |\n| `openapi`    | `pydantic_v2.BaseModel` | RCE on import |\n\nOther JSON-Schema-shaped inputs (`yaml`, `json`, `dict`, `csv`, `avro`, `protobuf`, `xmlschema`) follow the same code path and are expected to reproduce.\n\n### PoC\nSelf contained Proof of Concept is available at my secret gist: https://gist.github.com/thegr1ffyn/9648b0fe4fcf7d569ac8e61dd11eebaf\n\n### Impact\n\n- **Who's affected**: any developer or CI pipeline that runs `datamodel-codegen` against a schema they didn't author themselves — third-party API specs, schemas pulled from a registry, vendored upstream `.json` / `.yaml` / `.avsc` / `.proto` / `.xsd` files, schemas fetched from a remote URL or introspection endpoint — *and* who imports the generated `.py`.\n- **What it gains**: arbitrary Python code execution in the importer's process at `import` time. The PoC copies `/etc/passwd` to a tmp file to demonstrate arbitrary read; the same primitive supports any operation the importing process can perform (filesystem write, environment exfiltration, secondary network calls, RCE on CI runners).\n- **What it does NOT need**: no special CLI flags, no custom templates, no `--extra-template-data`, no `--use-schema-description`. Default invocation against a malicious schema is sufficient.\n- **What does block it**: choosing `--output-model-type typing.TypedDict` (which doesn't render `field()` / `Field()` calls). All other supported output model types are vulnerable.\n\n### Resolution\n\nThe fix validates schema-provided `default_factory` values while extracting JSON Schema field extras. Only the supported factory names `dict`, `list`, and `set` are accepted; any other value now raises a generator error before code generation. Generator-created default factories for supported mutable defaults and optional nested models continue to use the existing code paths.\n\n### Remediation\n\nUpgrade to `datamodel-code-generator` `0.60.2` or later.\n\nThis issue affects `datamodel-code-generator` versions `>= 0.17.0, <= 0.60.1` and is fixed in `0.60.2`.\n\nSubmitted by: Hamza Haroon (thegr1ffyn)\n\n## Affected packages\n\n- `datamodel-code-generator >= 0.17.0, < 0.60.2`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `datamodel-code-generator 0.60.2`","depth":"twilight","depthScore":48,"depthScoreParts":{"impact":48.4,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}