Alta

`datamodel-code-generator` vulnerable to code execution on import via unescaped `validators` entries in --extra-template-data

  • Publicada: 28.07.2026
  • Actualizado: 11.10.2026 14:19

Summary

When the Pydantic v2 output mode is in use, datamodel-code-generator reads a validators array from each model entry in the --extra-template-data file and synthesises a Pydantic @field_validator(...) decorator from each entry. The field names and the validator mode are interpolated into the decorator call wrapped in unescaped single quotes. A value containing ' breaks out of the string literal, letting an attacker emit an arbitrary positional Python expression into the decorator. The expression is evaluated at class-definition time, i.e. the moment the developer imports the generated module. This is the same trust model as the recently-published GHSA-wjv6-jcfj-mf9r (extras-file comment injection) but the impact is full RCE rather than a docstring leak.

Details

Sink: src/datamodel_code_generator/model/pydantic_v2/base_model.py, _process_validators (lines 405–449, at tag 0.60.1 / commit a321547e):

python
def _process_validators(self) -> None:
    validators = self.extra_template_data.get("validators")
    if not validators:
        return
    ...
    for validator in validators:
        fields = validator.get("fields") or [validator.get("field")]
        fields = [f for f in fields if f]
        if not fields:
            continue
        function_path: str = validator["function"]
        function_name = function_path.rsplit(".", 1)[-1]
        mode = validator.get("mode", "after")
        fields_str = ", ".join(f"'{f}'" for f in fields)     # (A) UNESCAPED
        ...
        mode_str = f"mode='{mode}'"                          # (B) UNESCAPED
        prepared_validators.append({
            "fields_str": fields_str,
            "mode_str":   mode_str,
            "method_name": method_name,
            "function_name": function_name,
            "mode": mode,
        })
        self._additional_imports.append(Import.from_full_path(function_path))  # (C)

The strings from (A) and (B) flow verbatim into src/datamodel_code_generator/model/template/pydantic_v2/BaseModel.jinja2:

jinja
@field_validator({{ v.fields_str }}, {{ v.mode_str }})

There is no repr() call, no identifier check, and no quote-escaping.

Secondary sink at (C): Import.from_full_path(function_path) splits on the last . and emits from <prefix> import <suffix>. A ; in function_path therefore lands in the generated import line and runs as a statement at module load.

PoC

A self-contained one-file PoC is available here: https://gist.github.com/thegr1ffyn/34d5c647e74487ffb2be27c76dace2aa

Impact

Arbitrary code execution in the developer's interpreter / CI runner the moment the generated module is imported. Anyone who accepts a --extra-template-data file from an untrusted source is impacted:

  • Pull requests adding or modifying project-local *.template-data.json / .codegen.json files consumed by a make codegen rule or pre-commit hook.
  • Configuration snippets pasted from issue templates, READMEs, or third-party guides.
  • Multi-tenant CI systems where one tenant's config file is read by another tenant's build.

Same blast radius as GHSA-wjv6-jcfj-mf9r, but silent RCE rather than a docstring leak — significantly higher impact under the same threat model.

Introduced in 0.52.1 by commit a2b27562 (Add --validators option for Pydantic v2 field validators).

Resolution

The fix validates validators entries with Pydantic models before rendering them. Field names must be valid non-keyword Python identifiers, function must be a dotted Python identifier path, and mode must be one of Pydantic's supported validator modes. The generated decorator arguments now render field names with repr() and mode with !r, so validated values are still emitted as Python string literals.

Remediation

Upgrade to datamodel-code-generator 0.60.2 or later.

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

Submitted by: Hamza Haroon (thegr1ffyn)

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Python (PyPI) datamodel-code-generator >= 0.52.1, < 0.60.2 0.60.2

Referencias

Puntuación CVSS 7.8/10
Vector CVSS
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Debilidad (CWE)
CWE-94
Plataforma
Python (PyPI)
Paquete
datamodel-code-generator
Publicada
28.07.2026
Actualizado
11.10.2026 14:19

Fuentes y licencias

OSV / GitHub Advisory Database - PYSEC-2026-3559 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-8m8r-38jm-f355 - CC BY 4.0

Historial de vulnerabilidades: datamodel-code-generator

Todas las vulnerabilidades publicadas de este paquete (Python (PyPI)), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (13) en el archivo
Entradas en total
13
Primera → última
07.2026 10.2026
Sin corrección
0
Explotada en ataques
0

Distribución por gravedad

  • Alta 12
  • Baja 1

Divulgaciones por año

  1. 2026: 13
Gravedad:
  1. `datamodel-code-generator` vulnerable to code execution on import via unescaped `validators` entries in --extra-template-data esta entrada
    Alta · 7.8 CVE-2026-54656 >= 0.52.1, < 0.60.2 0.60.2

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.