PT-2026-65638 · Pypi · Datamodel-Code-Generator
Published
2026-07-28
·
Updated
2026-07-28
CVSS v3.1
8.8
High
| Vector | AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
Summary
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.Details
The vulnerable chain spans the JSON-Schema-shaped parser and three sink locations (Pydantic v2, dataclass, msgspec):
Source — schema →
extras:src/datamodel code generator/parser/jsonschema.py:600-614—DEFAULT FIELD KEYSincludes the literal string"default factory".src/datamodel code generator/parser/jsonschema.py:457-459—JsonSchemaObject. initstores any non-standard key (includingdefault factory) inself.extras.src/datamodel code generator/parser/jsonschema.py:797-812—get field extraspreservesdefault factorythrough to the field model.
Sinks —
extras → generated Python expression:src/datamodel code generator/model/pydantic base.py:222-249:
python
default factory = data.pop("default factory", None)
...
if default factory is not None:
field arguments = [f"default factory={default factory}", *field arguments]The
default factory value is interpolated raw (no repr(), no validation).src/datamodel code generator/model/dataclass.py:211:
python
f"{k}={v if k == 'default factory' else repr(v)}"Explicit special-case to skip
repr() for default factory.src/datamodel code generator/model/msgspec.py:361— same pattern as dataclass.
Because
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.Confirmed PoC matrix
| Input file type | Output model type | Result |
|---|---|---|
jsonschema | pydantic v2.BaseModel | RCE on import |
jsonschema | dataclasses.dataclass | RCE on import |
jsonschema | msgspec.Struct | RCE on import |
jsonschema | typing.TypedDict | safe (TypedDict doesn't render field(); default factory silently dropped) |
openapi | pydantic v2.BaseModel | RCE on import |
Other JSON-Schema-shaped inputs (
yaml, json, dict, csv, avro, protobuf, xmlschema) follow the same code path and are expected to reproduce.PoC
Self contained Proof of Concept is available at my secret gist: https://gist.github.com/thegr1ffyn/9648b0fe4fcf7d569ac8e61dd11eebaf
Impact
- Who's affected: any developer or CI pipeline that runs
datamodel-codegenagainst a schema they didn't author themselves — third-party API specs, schemas pulled from a registry, vendored upstream.json/.yaml/.avsc/.proto/.xsdfiles, schemas fetched from a remote URL or introspection endpoint — and who imports the generated.py. - What it gains: arbitrary Python code execution in the importer's process at
importtime. The PoC copies/etc/passwdto 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). - 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. - What does block it: choosing
--output-model-type typing.TypedDict(which doesn't renderfield()/Field()calls). All other supported output model types are vulnerable.
Resolution
The 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.Remediation
Upgrade to
datamodel-code-generator 0.60.2 or later.This issue affects
datamodel-code-generator versions >= 0.17.0, <= 0.60.1 and is fixed in 0.60.2.Submitted by: Hamza Haroon (thegr1ffyn)
Fix
Code Injection
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Datamodel-Code-Generator