PYSEC-2026-3566

See a problem?
Import Source
https://github.com/pypa/advisory-database/blob/main/vulns/datamodel-code-generator/PYSEC-2026-3566.yaml
JSON Data
https://api.osv.dev/v1/vulns/PYSEC-2026-3566
Aliases
Published
2026-08-04T11:34:44.771231Z
Modified
2026-08-04T14:30:26.210993125Z
Severity
  • 7.8 (High) CVSS_V3 - CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H CVSS Calculator
Summary
`datamodel-code-generator` vulnerable to code injection via unescaped carriage return in `--extra-template-data` `comment` field
Details

Summary

datamodel-code-generator is vulnerable to code injection when a developer passes an --extra-template-data file whose comment value contains a literal \r (carriage return). The comment variable is rendered into a Python # comment in six built-in templates with no line-terminator escaping. Python's tokenizer treats a bare CR as a physical-line terminator (see Python language reference — Physical lines), so the comment ends at the \r and the text after it is parsed as Python, including, when the CR is followed by suitable indentation, as a statement within the class body that follows on the next template line.

Details

The vulnerable templates each contain # {{ comment }} with no escaping:

  • src/datamodel_code_generator/model/template/TypeAliasAnnotation.jinja2:12 and :19
  • src/datamodel_code_generator/model/template/TypeAliasType.jinja2:12 and :19
  • src/datamodel_code_generator/model/template/TypeStatement.jinja2:12 and :19
  • src/datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2:4
  • src/datamodel_code_generator/model/template/pydantic_v2/RootModel.jinja2:19
  • src/datamodel_code_generator/model/template/pydantic_v2/RootModelTypeAlias.jinja2:13

The pydantic_v2/BaseModel.jinja2:4 site is representative:

class {{ class_name }}({{ base_class }}):{% if comment is defined %}  # {{ comment }}{% endif %}

When the developer-supplied extras file populates comment for a model, the value reaches the template via DataModel.extra_template_data (set in src/datamodel_code_generator/model/base.py:736-742) and Jinja2 interpolates it raw. None of the templates use comment_safe, escape_docstring, or any other line-terminator filter.

PoC

Complete self contained POC is available at my secret gist: https://gist.github.com/thegr1ffyn/8ad6b8cb3cc2be9d3a0144aeb6896a3f

Impact

  • Who's affected: any developer or CI pipeline that runs datamodel-codegen --extra-template-data <file> where the extras file is influenced by attacker-controlled input. Realistic scenarios include:
    • Extras file generated from a third-party schema-annotation system.
    • Extras file vendored from an upstream repository.
    • Extras file produced by a script that merges multiple comment sources.
    • Build pipelines that template the extras file from environment variables, ticket descriptions, or commit metadata.
  • What it gains: arbitrary Python code execution in the importer's process at import time.
  • What it does NOT need: the schema itself can be entirely benign; only the extras file needs to contain the malicious comment.
  • What does block it: not passing --extra-template-data, or rejecting extras files whose comment values contain \r, \x0b, or \x0c before invocation.

Resolution

The fix normalizes comment values from built-in --extra-template-data before template rendering. Inline comments now convert CRLF, bare CR, vertical tab, and form feed into LF and prefix continuation lines with #, so attacker-controlled text stays inside the generated Python comment block.

Remediation

Upgrade to datamodel-code-generator 0.60.2 or later.

This issue affects datamodel-code-generator versions >= 0.14.1, <= 0.60.1 and is fixed in 0.60.2.

Submitted by: Hamza Haroon (thegr1ffyn)

References

Affected packages

PyPI / datamodel-code-generator

Package

Name
datamodel-code-generator
View open source insights on deps.dev
Purl
pkg:pypi/datamodel-code-generator

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0.14.1
Fixed
0.60.2

Affected versions

0.*
0.14.1
0.15.0
0.16.0
0.16.1
0.17.0
0.17.1
0.17.2
0.18.0
0.18.1
0.19.0
0.20.0
0.21.0
0.21.1
0.21.2
0.21.3
0.21.4
0.21.5
0.22.0
0.22.1
0.23.0
0.24.0
0.24.1
0.24.2
0.25.0
0.25.1
0.25.2
0.25.3
0.25.4
0.25.5
0.25.6
0.25.7
0.25.8
0.25.9
0.26.0
0.26.1
0.26.2
0.26.3
0.26.4
0.26.5
0.27.0
0.27.1
0.27.2
0.27.3
0.28.0
0.28.1
0.28.2
0.28.3
0.28.4
0.28.5
0.29.0
0.30.0
0.30.1
0.30.2
0.31.0
0.31.1
0.31.2
0.32.0
0.33.0
0.34.0
0.35.0
0.36.0
0.37.0
0.38.0
0.39.0
0.40.0
0.41.0
0.42.0
0.42.1
0.42.2
0.43.0
0.43.1
0.44.0
0.45.0
0.46.0
0.47.0
0.48.0
0.49.0
0.50.0
0.51.0
0.52.0
0.52.1
0.52.2
0.53.0
0.54.0
0.54.1
0.55.0
0.56.0
0.56.1
0.57.0
0.58.0
0.59.0
0.59.1
0.60.0
0.60.1

Database specific

source
"https://github.com/pypa/advisory-database/blob/main/vulns/datamodel-code-generator/PYSEC-2026-3566.yaml"