
Injeção de código (RCE) no datamodel-code-generator via customBasePath não validado (CVE-2026-63720)
Gravidade: Alta, CVSS 3.1 7.5 / CVSS 4.0 7.5 (atribuída pela VulnCheck, a CNA)
Teto ambiental (implantação como serviço de rede): até 9.8
Vetor (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
Vetor (v3.1): CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
Afetados: datamodel-code-generator < 0.70.0
Corrigido em: 0.70.0
CWE: CWE-94 (Controle Impróprio da Geração de Código, 'Injeção de Código')
Relatado por: Rahul Karne
CNA: VulnCheck
Publicado: 26 de julho de 2026
O datamodel-code-generator validou todas as strings de importação controladas pelo schema que poderiam carregar um payload de injeção de código, exceto uma.
A ferramenta converte um schema de entrada (JSON Schema, OpenAPI, YAML) em código-fonte de modelos Python. Vários campos do schema são renderizados diretamente nesse código gerado, então o projeto os valida como identificadores Python pontilhados antes do uso, especificamente para prevenir injeção. O campo de extensão do schema customBasePath é o único irmão que pula essa verificação. Seu valor flui sem sanitização para uma instrução from ... import ... na saída gerada. Um atacante que controla o schema de entrada pode embutir Python arbitrário usando quebras de linha e uma expressão sem pontos, e ele é executado no momento em que o módulo gerado é importado, que é o passo seguinte habitual após gerar os modelos.
Esta é uma correção incompleta da CVE-2026-55415 (GHSA-5578-w22f-pfx9), que endureceu os campos irmãos customTypePath e x-python-import contra exatamente essa classe. Essa correção não cobriu o customBasePath, que atinge o mesmo sink sem validação e permaneceu explorável até 0.68.1 e na main até 0.70.0.
Execução arbitrária de código Python no processo que importa ou executa os modelos gerados: a máquina do desenvolvedor, um runner de CI ou qualquer serviço que gera e depois carrega modelos. A confidencialidade, a integridade e a disponibilidade do host são totalmente comprometidas, limitadas apenas pelos privilégios desse processo.
A gravidade depende inteiramente de onde o codegen roda sobre entrada não confiável:
Quem é afetado: Qualquer uso do datamodel-code-generator < 0.70.0 que (1) gera modelos a partir de um schema cujo valor de customBasePath é influenciado pelo atacante e (2) importa ou executa o módulo gerado. O fluxo padrão de gerar-e-depois-importar satisfaz (2) inerentemente.
Quem não é afetado:
customBasePath é validado.| Métrica | Valor | Fonte |
|---|---|---|
| Downloads, todos os tempos | 194 milhões | pepy.tech/projects/datamodel-code-generator |
| Downloads, últimos 30 dias | 16.3 milhões | pepy.tech |
| Implantação típica | Máquinas de desenvolvedores, pipelines de CI/CD e plataformas de geração de SDKs que fazem codegen a partir de OpenAPI / JSON Schema | inerente à função da ferramenta |
O valor do campo de schema customBasePath é levado para o código gerado sem nenhuma restrição de identificador. Três pontos do codebase importam (caminhos relativos a src/datamodel_code_generator/):
parser/jsonschema.py define o campo custom_base_path com alias="customBasePath" (~linha 644), consumido via _resolve_base_class(...) em vários pontos de chamada.parser/base.py, _resolve_base_class (~linha 1665), retorna o valor após apenas um normalize() local (dedup/trim). Nenhuma validação de identificador é aplicada.imports.py, Import.from_full_path() (~linha 35), emite o valor literalmente como uma linha from ... import .... O valor também é usado como base da classe em model/base.py set_base_class (~linha 1324) e renderizado cru pelo template do modelo (class {{ class_name }}({{ base_class }}):).Como o valor é escrito no código-fonte Python sem nenhuma restrição, quebras de linha embutidas e uma expressão sem pontos sobrevivem na saída como linhas próprias e individualmente analisáveis, e a linha do meio é executada na importação.
O payload é necessariamente sem pontos. Import.from_full_path divide o valor por ., então uma chamada normal os.system(...) seria desmembrada. Usar getattr(__import__('os'),'system')(...) evita qualquer . enquanto ainda resolve a mesma chamada, e as quebras de linha ao redor mantêm as linhas from ... import ... emitidas sintaticamente válidas, de modo que a linha do meio injetada roda sem problemas.
Este não é um projeto que negligenciou injeção. O mantenedor endureceu exatamente essa classe repetidamente em vários advisories (GHSA-5578, m34r, 8m8r, wjv6), sempre encaminhando strings de importação ou de tipo controladas pelo schema por _validate_dotted_python_identifier_path antes de chegarem à geração de código. Os campos irmãos customTypePath (validado em parser/jsonschema.py ~linhas 4956, 5202) e x-python-import (~linha 2096) passam por esse validador.
O customBasePath é o único irmão sem essa chamada. Ele atinge o mesmo sink Import.from_full_path por um caminho diferente (_resolve_base_class) que nunca foi ligado à validação que os outros campos receberam. O defeito sobreviveu justamente porque a defesa ao redor parecia completa: um revisor que procura strings de importação não validadas vê validadores nos campos que verifica primeiro, e este aqui passa por um helper que parece resolução de classe base, não tratamento de importação. É uma lacuna em uma correção sistemática, não uma ausência dela, e é por isso que persistiu até a versão mais recente.
Um atacante precisa de:
< 0.70.0.customBasePath em um schema que o alvo processará, na prática fornecendo ou influenciando o schema de entrada (um documento OpenAPI/JSON Schema de terceiros, ou um schema enviado a um serviço).Nenhuma autenticação ou privilégios elevados são exigidos do atacante (PR:N). A pontuação base reflete que a vítima executa a ação comum de gerar-e-importar (UI:R na v3.1 / UI:A na v4.0); a implantação como serviço de rede remove até isso, e é daí que vem o 9.8 ambiental.
O seguinte foi executado contra o pacote real, sem modificações. Reprodução:
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"
Entrada do atacante (attack.json):
{
"type": "object",
"title": "User",
"customBasePath": "builtins import object\ngetattr(__import__('os'),'system')('whoami > RCE_PROOF.txt')\nfrom builtins.object",
"properties": { "name": { "type": "string" } }
}
generated_models.py gerado na versão vulnerável (0.68.1):
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
A chamada do atacante é emitida literalmente no código-fonte gerado.
Na importação: o comando é executado. Na execução verificada, o marcador injetado foi impresso no stdout e RCE_PROOF.txt foi criado contendo o usuário atual (root), confirmando a execução arbitrária de comandos pelo fluxo comum de gerar-e-importar.
Na versão corrigida (0.70.0): o mesmo schema é rejeitado antes que qualquer código seja gerado:
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"
Nenhum arquivo é produzido. A mensagem de rejeição nomeia a correção diretamente: o valor agora precisa ser um caminho de identificador Python pontilhado.
Variante como serviço de rede. Foi demonstrado um serviço HTTP de loopback não autenticado que aceita um schema enviado via POST, gera modelos e os importa, executando o comando do atacante no servidor a partir de um único curl não autenticado, sem interação do usuário. Este é o formato de implantação por trás do 9.8 ambiental. Os arquivos do serviço e do ataque estão incluídos no repositório da PoC.
Atualize para datamodel-code-generator 0.70.0 ou posterior:
pip install --upgrade "datamodel-code-generator>=0.70.0"
A versão 0.70.0 encaminha o customBasePath pela mesma validação de identificador pontilhado já aplicada a customTypePath e x-python-import, de modo que um valor que não seja um caminho de identificador válido é rejeitado antes da geração de código.
Se você não puder atualizar imediatamente: não gere modelos a partir de schemas que você não controla totalmente e não importe nem execute módulos gerados a partir de schemas não confiáveis. Não existe uma flag de configuração que adicione a validação ausente nas versões afetadas; atualizar é a correção confiável.
Nota para quem reutiliza os internos do gerador. O defeito era uma chamada de validação ausente em um caminho de código até Import.from_full_path, não uma falha no próprio sink. Qualquer projeto downstream que renderize strings controladas pelo schema em código gerado deve validar cada um desses campos como identificador pontilhado, não apenas os que passam pelo caminho óbvio de tratamento de importação.
A VulnCheck (a CNA) atribuiu 7.5 (Alta), correspondendo ao vetor base que o mantenedor usou para o advisory pai CVE-2026-55415, porque é a mesma classe de injeção, o mesmo sink Import.from_full_path e o mesmo impacto.
AV:N: schemas são comumente obtidos pela rede (documentos OpenAPI / JSON Schema obtidos ou de terceiros).AC:H: a exploração depende de a vítima gerar modelos a partir do schema malicioso e então importar ou executar o código gerado.PR:N / UI:R (v3.1): sem privilégios do atacante; a vítima executa o fluxo comum de codegen-e-importação.C:H / I:H / A:H: execução arbitrária e completa de código no host.O teto ambiental é 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) e se aplica especificamente à implantação como serviço de rede, onde o gerador fica exposto a schemas não confiáveis e nenhuma interação da vítima é necessária. Esse número é uma nota ambiental para essa implantação, não a pontuação base atribuída. Apresentar ambos, e ser explícito sobre qual é qual, é o enquadramento honesto: a base é 7.5, e chega a 9.8 apenas no caso de serviço exposto.
| Data | Evento |
|---|---|
| 13 de julho de 2026 | Vulnerabilidade identificada |
| 14 de julho de 2026 | Relatada (divulgação coordenada) |
| 21 de julho de 2026 | Correção enviada (545a96c5) |
| 24 de julho de 2026 | Versão corrigida 0.70.0 lançada |
| 26 de julho de 2026 | CVE-2026-63720 publicada pela VulnCheck |
Descoberta e relatada por Rahul Karne, pesquisador de segurança e Membro Sênior da IEEE. Sua pesquisa foca em falhas de injeção e de tratamento de entrada em pacotes open-source de alta dependência, incluindo a CVE-2026-65321 (injeção de SQL no PyAthena) e o endurecimento da classe pai em torno desta descoberta.
Contato: [email protected] · GitHub: rahulreddykarne
545a96c5: https://github.com/koxudaxi/datamodel-code-generator/commit/545a96c5Consultas da imprensa: [email protected]. PoC completo (schema do atacante, demonstração como serviço de rede) e detalhes técnicos adicionais disponíveis mediante solicitação.