
Code-Injection (RCE) in datamodel-code-generator über nicht validierten customBasePath (CVE-2026-63720)
Schweregrad: Hoch, CVSS 3.1 7.5 / CVSS 4.0 7.5 (zugewiesen von VulnCheck, der CNA)
Umgebungs-Obergrenze (Netzwerkdienst-Bereitstellung): bis zu 9.8
Vektor (v4.0): CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Vektor (v3.1): CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
Betroffen: datamodel-code-generator < 0.70.0
Behoben in: 0.70.0
CWE: CWE-94 (Unzureichende Kontrolle der Codegenerierung, 'Code-Injection')
Gemeldet von: Rahul Karne
CNA: VulnCheck
Veröffentlicht: 26. Juli 2026
datamodel-code-generator validierte jeden schema-kontrollierten Import-String, der eine Code-Injection-Payload tragen konnte, bis auf einen.
Das Tool konvertiert ein Eingabeschema (JSON Schema, OpenAPI, YAML) in Python-Modellquellcode. Mehrere Schemafelder werden direkt in diesen generierten Code gerendert, daher validiert das Projekt sie vor der Verwendung als Dotted-Python-Identifier, speziell um Injection zu verhindern. Das Schema-Erweiterungsfeld customBasePath ist das eine Geschwisterfeld, das diese Prüfung überspringt. Sein Wert fließt unbereinigt in eine from ... import ...-Anweisung im generierten Output. Ein Angreifer, der das Eingabeschema kontrolliert, kann beliebiges Python mithilfe von Zeilenumbrüchen und einem punktfreien Ausdruck einbetten, und es wird in dem Moment ausgeführt, in dem das generierte Modul importiert wird – der übliche nächste Schritt nach der Modellgenerierung.
Dies ist eine unvollständige Behebung von CVE-2026-55415 (GHSA-5578-w22f-pfx9), die die Geschwisterfelder customTypePath und x-python-import gegen genau diese Klasse gehärtet hat. Diese Behebung deckte customBasePath nicht ab, das unvalidiert zum identischen Sink gelangt und bis 0.68.1 sowie in main bis 0.70.0 ausnutzbar blieb.
Beliebige Python-Codeausführung in dem Prozess, der die generierten Modelle importiert oder ausführt: auf dem Rechner des Entwicklers, einem CI-Runner oder jedem Dienst, der Modelle generiert und anschließend lädt. Vertraulichkeit, Integrität und Verfügbarkeit des Hosts sind vollständig kompromittiert, begrenzt nur durch die Berechtigungen dieses Prozesses.
Der Schweregrad hängt vollständig davon ab, wo Codegen mit nicht vertrauenswürdigem Input läuft:
Wer ist betroffen: Jede Verwendung von datamodel-code-generator < 0.70.0, die (1) Modelle aus einem Schema generiert, dessen customBasePath-Wert vom Angreifer beeinflusst ist, und (2) das generierte Modul importiert oder ausführt. Der Standard-Workflow Codegen-dann-Import erfüllt (2) von Natur aus.
Wer ist nicht betroffen:
0.70.0 oder neuer verwenden, wo customBasePath validiert wird.| Metrik | Wert | Quelle |
|---|---|---|
| Downloads, gesamt | 194 Millionen | pepy.tech/projects/datamodel-code-generator |
| Downloads, letzte 30 Tage | 16,3 Millionen | pepy.tech |
| Typische Bereitstellung | Entwickler-Rechner, CI/CD-Pipelines und SDK-Generierungsplattformen, die Codegen aus OpenAPI / JSON Schema betreiben | in der Funktion des Tools begründet |
Der Wert des Schemafelds customBasePath wird ohne Identifier-Einschränkung in den generierten Code übernommen. Drei Punkte in der Codebasis sind relevant (Pfade relativ zu src/datamodel_code_generator/):
parser/jsonschema.py definiert das Feld custom_base_path mit alias="customBasePath" (~Zeile 644), das über _resolve_base_class(...) an mehreren Aufrufstellen konsumiert wird.parser/base.py, _resolve_base_class (~Zeile 1665), gibt den Wert nur nach einem lokalen normalize() zurück (Deduplizierung/Trimmen). Es wird keine Identifier-Validierung angewendet.imports.py, Import.from_full_path() (~Zeile 35), gibt den Wert wörtlich als from ... import ...-Zeile aus. Der Wert wird auch als Klassenbasis in model/base.py set_base_class (~Zeile 1324) verwendet und von der Modellvorlage roh gerendert (class {{ class_name }}({{ base_class }}):).Da der Wert ohne Einschränkung in den Python-Quellcode geschrieben wird, bleiben eingebettete Zeilenumbrüche und ein punktfreier Ausdruck im Output als eigene, einzeln parsebare Zeilen erhalten, und die mittlere Zeile wird beim Import ausgeführt.
Die Payload ist notgedrungen punktfrei. Import.from_full_path teilt den Wert an . auf, sodass ein normaler os.system(...)-Aufruf auseinandergerissen würde. Durch die Verwendung von getattr(__import__('os'),'system')(...) wird jeder . vermieden, während derselbe Aufruf weiterhin aufgelöst wird; die umgebenden Zeilenumbrüche halten die ausgegebenen from ... import ...-Zeilen syntaktisch gültig, sodass die injizierte mittlere Zeile sauber läuft.
Dies ist kein Projekt, das Injection vernachlässigt hat. Der Maintainer hat genau diese Klasse wiederholt über mehrere Advisories gehärtet (GHSA-5578, m34r, 8m8r, wjv6), indem er jedes Mal einen schema-kontrollierten Import- oder Typ-String durch _validate_dotted_python_identifier_path leitete, bevor dieser die Codegenerierung erreicht. Die Geschwisterfelder customTypePath (validiert bei parser/jsonschema.py ~Zeilen 4956, 5202) und x-python-import (~Zeile 2096) durchlaufen beide diesen Validator.
customBasePath ist das eine Geschwisterfeld ohne einen solchen Aufruf. Es erreicht denselben Import.from_full_path-Sink über einen anderen Pfad (_resolve_base_class), der nie in die Validierung eingebunden wurde, die die anderen Felder erhielten. Der Defekt überlebte genau deshalb, weil die umgebende Verteidigung vollständig wirkte: Ein Prüfer, der nach unvalidierten Import-Strings sucht, sieht Validatoren auf den Feldern, die er zuerst prüft, und dieses Feld führt über einen Helfer, der wie Basisklassen-Auflösung aussieht statt wie Import-Behandlung. Es ist eine Lücke in einer systematischen Behebung, keine gänzlich fehlende, weshalb es bis in die neueste Version überdauerte.
Ein Angreifer benötigt: