Answer in brief
CVE-2026-54654 records a High severity secret exfiltration vulnerability in `datamodel-code-generator` vulnerable to code injection via unescaped carriage return in `--extra-template-data` `comment` field. The source record does not mark it as known exploited. 1 affected package is mapped in the feed.
Answer in brief
CVE-2026-54654 records a High severity secret exfiltration vulnerability in `datamodel-code-generator` vulnerable to code injection via unescaped carriage return in `--extra-template-data` `comment` field. The source record does not mark it as known exploited. 1 affected package is mapped in the feed.
Update datamodel-code-generator to 0.60.2 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanSecret Exfiltration describes the vulnerability class recorded for this advisory. The current record does not mark CVE-2026-54654 as known exploited; continue to monitor the source for status changes. The feed includes package mappings that can be checked against lockfiles and deployed manifests.
| Package | Affected range | Fixed version |
|---|---|---|
| datamodel-code-generatorpip | >=0.14.1,<=0.60.1 | 0.60.2 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
CVE-2026-54654 records a High severity secret exfiltration vulnerability in `datamodel-code-generator` vulnerable to code injection via unescaped carriage return in `--extra-template-data` `comment` field. The source record does not mark it as known exploited. 1 affected package is mapped in the feed.
The source record does not mark it as known exploited.
Check lockfiles and deployed manifests for datamodel-code-generator.
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL GuardUpdate datamodel-code-generator to 0.60.2 if you use the affected versions. Test the change in a non-production environment first.
Local check
hol-guard supply-chain scanSecret Exfiltration describes the vulnerability class recorded for this advisory. The current record does not mark CVE-2026-54654 as known exploited; continue to monitor the source for status changes. The feed includes package mappings that can be checked against lockfiles and deployed manifests.
| Package | Affected range | Fixed version |
|---|---|---|
| datamodel-code-generatorpip | >=0.14.1,<=0.60.1 | 0.60.2 |
Fixed versions are reported by the source feed; confirm compatibility before updating.
Reported by GitHub Security Advisories (ghsa).
CVE-2026-54654 records a High severity secret exfiltration vulnerability in `datamodel-code-generator` vulnerable to code injection via unescaped carriage return in `--extra-template-data` `comment` field. The source record does not mark it as known exploited. 1 affected package is mapped in the feed.
The source record does not mark it as known exploited.
Check lockfiles and deployed manifests for datamodel-code-generator.
HOL Guard can help your team review package activity against supported protection paths.
Explore HOL Guard### 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](https://docs.python.org/3/reference/lexical_analysis.html#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: ```jinja2 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)
### 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](https://docs.python.org/3/reference/lexical_analysis.html#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: ```jinja2 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)