# `datamodel-code-generator` vulnerable to code injection via unescaped carriage return in GraphQL Union description

GraphQL Union descriptions with a literal \r escape break out of generated Python comments in datamodel-code-generator, injecting code that runs on import of the model.

- Payout: Research
- Severity: high
- Program: datamodel-code-generator
- Found by: thegr1ffyn
- Disclosed: 2026-07-28
- CVE: CVE-2026-54621
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-j884-q54q-mmx3
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-j884-q54q-mmx3
- Tags: area:oss domain:oss impact:rce kind:research platform:ghsa sev:high tech:graphql tech:python technique:parser-differential technique:source-review vuln:command-injection

**Target:** GraphQL-to-Python code generator (Jinja2 Union templates)
**Root cause:** Union descriptions are rendered as Python comments via `# {{ description | replace('\n', '\n# ') }}`, which normalizes LF but not bare CR; Python's tokenizer treats CR as a physical line terminator, ending the comment early.
**Steps:**
1. Craft a GraphQL schema with a Union type whose description is a regular string containing a literal `\r` escape followed by Python code.
2. Run `datamodel-codegen --input-file-type graphql` on the schema.
3. Generated .py contains `# <desc>` where the CR terminates the comment and the trailing text becomes module-level Python.
4. Import the generated module; injected code executes with the importer's privileges.
**How found:** Reporter noticed the Union comment templates only replaced `\n` and reasoned that Python's lexer also treats bare CR as a line terminator, allowing comment escape; graphql-core preserves `\r` escapes in regular strings (block strings normalize line endings).
**Exploitation:** Attacker supplies or influences a GraphQL schema processed by datamodel-codegen; the generated model file carries module-level Python that executes at import time in developer environments, CI pipelines, or apps importing the model. No special flags or custom templates needed.
**Insight:** When sanitizing text for embedding in a target language's comments, enumerate every line terminator that language's lexer accepts (CR, LF, CRLF, and Unicode line separators), not just `\n`; GraphQL regular strings preserve `\r` while block strings normalize it, so test both forms.

