Node2Shell(CVE-2026-111497): Node.js Brotli 원격 코드 실행 취약점과 패치 버전

Node2Shell은 Node.js에 내장된 Brotli 디코더의 메모리 범위 밖 쓰기(out-of-bounds write) 취약점 CVE-2026-111497을 부르는 별칭입니다. 조작된 Brotli 데이터 하나로 Node.js 프로세스를 죽이거나 메모리 내용을 빼낼 수 있고 일부 환경에서는 공격자 코드까지 실행할 수 있습니다. Node.js는 2026년 10월 21일 22.23.4, 24.22.1, 26.12.1 버전으로 이를 고쳤고 발견자로 OpenAI의 보안 에이전트 Codex Security를 명시했습니다. 외부에서 들어온 Brotli 데이터를 압축 해제하는 서비스라면 지금 바로 업데이트해야 합니다.
문제는 Node.js 자체 코드가 아니라 Google의 Brotli 라이브러리에 있었습니다. 그래서 같은 라이브러리를 품은 Bun, Envoy, 파이썬 Brotli 패키지도 각자 패치를 내야 했습니다. 패치가 나온 다음 날에는 보안 업체 Imperva가 수정되지 않은 공식 Node.js 이미지에서 코드 실행에 성공했다고 발표했습니다.
핵심 요약
- Node.js 10월 보안 릴리스 기준 수정 버전은 22.23.4, 24.22.1, 26.12.1입니다. 지원이 끝난 25.x, 20.x 계열에는 패치가 나오지 않습니다.
- CVE를 발급한 Google은 CVE 레코드에서 CVSS v4.0 9.2점을 매겼습니다. Node.js는 심각도를 High로 분류했습니다.
- Node.js는 제보자를 "OpenAI Codex Security(Khai Tran, Sylvie Mayer)"로 적었고 Envoy 권고문은 OpenAI Security Research를 제보자로 밝혔습니다.
- 공개 개념증명(PoC) 코드가 있습니다. Imperva는 Linux arm64용 Node.js 24.22.0에서 코드 실행에 성공했습니다. 10월 24일 기준으로 실제 공격 사례는 확인되지 않았습니다.
- 가장 위험한 곳은 신뢰할 수 없는 서버에
fetch()를 보내는 앱, body-parser 2를 쓰는 Express 5 서버, 외부 입력을node:zlib로 Brotli 압축 해제하는 코드입니다.
Node2Shell(CVE-2026-111497)은 어떤 취약점인가
CVE-2026-111497은 Google Brotli 1.0.3부터 1.2.0까지의 압축 해제 코드(c/dec/decode.c)에 있는 메모리 안전성 버그입니다. CVE 레코드는 이를 버퍼 오버플로로 설명합니다. 인증 없이 원격에서 조작한 Brotli 압축 스트림만 보내도 디코더 메모리를 오염시키고 메모리 내용을 노출하고 서비스를 멈추게 할 수 있으며 임의 코드 실행으로 이어질 가능성도 있다는 내용입니다.
Brotli는 HTTP Content-Encoding 헤더에 br로 표시되는 압축 형식입니다. 브라우저와 CDN, 웹 서버가 널리 씁니다. Node.js는 node:zlib를 지원하려고 디코더 사본을 자체적으로 포함해 배포합니다.
Node.js 권고문은 원인을 이렇게 설명합니다. 잘못된 블록 전환을 영구적인 형식 오류가 아니라 입력이 더 필요하다는 일시적 상태로 보고했고 그 결과 스트리밍 디코더가 8바이트짜리 내부 버퍼에 입력 바이트를 계속 덧붙였다는 것입니다. 쉽게 말해 압축 데이터 속 불가능한 지시를 만난 디코더가 이를 "바이트를 더 기다리라"는 뜻으로 오해했고 작은 버퍼 끝을 넘어 계속 썼습니다. CVE 레코드는 이 버그를 CWE-787(범위 밖 쓰기)과 CWE-252(반환값 미확인)로 분류했습니다.
Google은 10월 21일 GitHub에 수정판 Brotli 1.0.10, 1.1.1, 1.2.1을 올렸습니다. 수정 후 디코더는 해당 전환을 형식 오류로 처리해 바로 멈춥니다.
이름이 Node2Shell인 이유
이름은 Imperva가 10월 22일 공개한 연구 글 "Node2Shell: From Brotli Data to Remote Code Execution"에서 나왔습니다. 최근 원격 코드 실행 버그에 붙는 "-2Shell" 작명을 따른 것으로, 같은 날 패치가 나온 PHP2Shell도 이런 이름입니다. "Shell"은 공격자가 서버에서 명령 셸을 얻을 수 있다는 뜻인데, 지금까지는 시험 환경 한 곳에서만 확인됐습니다.

영향받는 버전과 수정 버전
현재 지원 중인 22.x, 24.x, 26.x 계열은 수정 버전 이전 릴리스가 모두 영향을 받습니다. 지원이 끝난(EOL) 계열도 전부 해당합니다. Node.js는 보안 릴리스가 나올 때 EOL 버전은 "항상 영향을 받는다"고 밝히고 있습니다.
| 제품 | 취약 버전 | 수정 버전 | 출처 |
|---|---|---|---|
| Node.js 26.x (Current) | 26.12.1 이전 | 26.12.1 | Node.js 권고문 |
| Node.js 24.x (LTS) | 24.22.1 이전 | 24.22.1 | Node.js 권고문 |
| Node.js 22.x (LTS) | 22.23.4 이전 | 22.23.4 | Node.js 권고문 |
| Node.js 25.x, 20.x 및 이전 | 전체 | 패치 없음(지원 종료) | Node.js 권고문 |
| Google Brotli (C 라이브러리) | 1.0.3~1.2.0 | 1.0.10, 1.1.1, 1.2.1 | CVE 레코드 |
| Bun | 1.4.3 이하 | 1.4.4 | Bun v1.4.4 릴리스 노트 |
| Envoy (Brotli 압축 해제 설정 시) | v1.39.2, v1.38.5, v1.37.7, v1.36.11 | v1.40.0, v1.39.3, v1.38.6, v1.37.8, v1.36.12 | GHSA-3wvj-j6qm-62mr |
파이썬 Brotli / brotlicffi | 1.2.0 이하 | 1.2.1 / 1.2.1.0 | PyPI: Brotli, PyPI: brotlicffi |
데비안 brotli 패키지 | bookworm 1.0.9-2, trixie 1.1.0-2 | 1.0.9-2+deb12u1, 1.1.0-2+deb13u1 | 데비안 보안 트래커 |
npm의 brotli 패키지는 이 취약점과 관계가 없어서 업데이트해도 소용이 없습니다. 취약한 코드는 Node.js 런타임 바이너리 안에 있습니다. 데비안은 예외입니다. 데비안의 nodejs 패키지는 시스템 Brotli 라이브러리를 링크하므로, 데비안에서는 Node.js 버전이 아니라 brotli 패키지 업데이트로 수정이 들어옵니다.
같은 Node.js 릴리스에서 CVE 9건이 함께 수정됐습니다. 이 가운데 High 등급은 DNS 이름 잘림 버그(CVE-2026-105482)와 TLS 호스트명 검증 우회 두 건(CVE-2026-105483, CVE-2026-106069)입니다.
실제로 위험한 서비스는 어디인가
취약한 Node.js 버전을 쓰는 것만으로 공격당하지는 않습니다. 공격자가 손댈 수 있는 Brotli 데이터가 디코더까지 들어가야 합니다. Node.js 권고문도 애플리케이션이 node:zlib로 압축 해제하는 Brotli 데이터를 공격자가 넣을 수 있을 때 프로세스 메모리가 오염된다고 설명합니다. 실제로 그런 데이터가 들어오는 길은 크게 세 가지입니다.
- 외부로 보내는
fetch()요청: Node.js 내장fetch()는Content-Encoding: br응답을 자동으로 디코딩합니다. 링크 미리보기, 웹훅, 스크래퍼, 웹을 돌아다니는 AI 에이전트처럼 사용자가 준 URL을 가져오는 서비스는 악성 응답을 받을 수 있습니다. - 들어오는 요청 본문: body-parser README에 따르면 모든 파서가
gzip,br(brotli),deflate를 자동으로 풀고inflate옵션 기본값도true입니다. Express 5는 body-parser 2를 쓰므로 외부에 열린 Express 5 API는 기본 설정에서 Brotli 본문을 디코딩합니다. Sysdig는 Koa(co-body 사용)와@fastify/compress를 쓰는 Fastify도 꼽았습니다. node:zlib직접 호출: 업로드 파일이나 큐 메시지에brotliDecompress,brotliDecompressSync,createBrotliDecompress를 쓰는 코드입니다.
자기 데이터만 압축 해제하는 내부 도구는 우선순위가 낮습니다. 그래도 업데이트는 해야 합니다. 서드파티 API 응답처럼 팀이 미처 신경 쓰지 못한 곳에서 Brotli 데이터가 들어올 수 있기 때문입니다.
OpenAI Codex Security가 찾아낸 버그
Node.js는 제보자로 "OpenAI Codex Security(Khai Tran, Sylvie Mayer)"를 밝혔습니다. Codex Security는 코드베이스에서 취약점을 찾고 검증하고 고치는 OpenAI의 애플리케이션 보안 에이전트로, 리서치 프리뷰로 출시됐습니다. 같은 CVE에 대한 Envoy 권고문은 "OpenAI Security Research"를 제보자로 적었습니다.
Node.js 패치가 나온 10월 21일은 PHP2Shell 패치가 나온 날이기도 합니다. PHP2Shell 역시 AI를 활용한 감사로 오래된 버그를 실제 공격 코드로 만든 사례입니다. 두 경우 모두 AI 도구가 여러 프로젝트가 함께 쓰는 오래된 C 코드를 읽었고 그 코드를 포함한 프로젝트들이 각자 패치를 내야 했습니다. 같은 날 터진 LiteLLM 공급망 공격은 성격이 다른 사건이지만 존재조차 몰랐던 의존성이 위험이 된다는 점은 같습니다.
일정은 짧았습니다.
| 날짜(2026년) | 내용 |
|---|---|
| 10월 16일 | Google이 CVE-2026-111497 예약 |
| 10월 21일 | Google이 Brotli 1.0.10, 1.1.1, 1.2.1 공개, Node.js가 22.23.4, 24.22.1, 26.12.1 배포 |
| 10월 22일 | CVE 레코드 공개, 첫 공개 PoC 등장, Imperva가 코드 실행 성공 발표, Bun 1.4.4와 파이썬 Brotli 1.2.1, brotlicffi 1.2.1.0 배포 |
| 10월 23일 | Envoy가 GHSA-3wvj-j6qm-62mr 공개 |
| 10월 24일 | Sysdig, 실제 공격 사례 미확인 보고 |
실제 위험도는 어느 정도인가
프로세스를 죽이기는 쉽지만 코드를 실행하기는 어렵습니다. Imperva의 Ron Masas는 공식 Node.js 24.22.0 Linux arm64 이미지에서 코드 실행에 성공했다고 밝혔습니다. 페이로드는 fetch()로 받은 HTTP 응답과 Express 요청 본문, 두 가지 방식으로 전달했습니다. 다만 "우리 환경에서도 여러 번 시도해야 했다"고 덧붙였습니다. Imperva는 공격 코드를 공개하지 않았고 Node.js 24.22.1은 같은 입력을 거부했습니다.
HeroDevs의 정리에 따르면 첫 공개 PoC는 일부러 보호 기능을 약하게 만든 테스트 빌드에서만 코드 실행에 성공했습니다. 표준 빌드에서는 프로세스가 죽고 메모리가 일부 읽히는 데 그쳤습니다. Bun, Envoy, 파이썬 패키지에서 코드 실행을 공개적으로 보여 준 사례는 아직 없습니다.
프로세스가 죽기만 해도 피해는 생깁니다. 잘못된 요청 하나로 Node.js 워커를 죽일 수 있다면 외부에 열린 Express 5 API를 아주 싸게 서비스 거부 공격할 수 있습니다. 메모리 유출로 프로세스가 들고 있던 토큰이나 키가 새어 나갈 수도 있습니다.
Node2Shell 패치와 확인 방법
- 런타임을 22.23.4, 24.22.1, 26.12.1로 올립니다. API 변경이 없는 패치 릴리스입니다.
- 실제로 돌고 있는 버전을 확인합니다. Dockerfile만 보지 말고 실행 중인 컨테이너마다
node --version을 실행하세요. Sysdig는 캐시된 이미지로 다시 빌드하면node:24같은 유동 태그가 예전 빌드를 그대로 쓸 수 있다고 경고합니다. 다시 빌드하기 전에 베이스 이미지를 새로 받으세요. - 컨테이너 이미지, 서버리스 번들, CI 러너, 단일 실행 파일 앱처럼 Node.js를 포함한 산출물을 모두 다시 빌드하고 프로세스를 재시작합니다.
- 지원이 끝난 계열에서 벗어납니다. Node.js 20, 25와 그 이전 버전에는 공식 패치가 나오지 않으니 22나 24로 옮기거나 유료 연장 지원 빌드를 쓰세요.
- 주변 구성 요소도 패치합니다. Bun은 1.4.4로, Envoy는 권고문에 나온 수정 버전으로, 파이썬
Brotli는 1.2.1로 올리고 배포판의brotli패키지도 업데이트합니다. - 배포가 끝날 때까지는 Imperva 권고대로 노출된 경로에서 외부 Brotli 트래픽을 임시로 제한합니다. body-parser에서
inflate옵션을false로 바꾸면 gzip을 포함한 모든 압축 본문이 거부되므로, 실제 클라이언트로 먼저 시험해 보세요. - 비정상 종료를 지켜봅니다. Imperva와 Sysdig 모두 예상치 못한 Node.js 종료나 디코더 오류를 공격의 증거가 아니라 조사할 단서로 봅니다. 크래시 직후 같은 컨테이너에서 새 프로세스가 실행되는 패턴에 알림을 걸어 두세요.
자주 묻는 질문
Node2Shell을 악용한 실제 공격이 있나요?
2026년 10월 24일 기준으로 Sysdig는 실제 공격 사례가 확인되지 않았다고 밝혔습니다. 미국 CISA도 10월 23일까지 CVE-2026-111497을 알려진 악용 취약점(KEV) 목록에 올리지 않았습니다. 하지만 공개 PoC가 있고 Imperva가 공식 Node.js 빌드에서 코드 실행을 보여 줬으니, KEV 등재를 기다리지 말고 지금 패치하는 편이 안전합니다.
npm의 "brotli" 패키지를 업데이트하면 CVE-2026-111497이 해결되나요?
아닙니다. 취약한 디코더는 Node.js 런타임 안에 컴파일돼 있습니다. Node.js 22.23.4, 24.22.1, 26.12.1 이상으로 올리거나, 데비안이라면 패치된 시스템 brotli 패키지를 설치해야 문제가 사라집니다.
Node.js 20을 쓰고 있다면 어떻게 해야 하나요?
Node.js 20은 지원이 끝나 CVE-2026-111497 공식 패치를 받지 못합니다. Node.js 22.23.4나 24.22.1로 올리세요. 당장 올릴 수 없다면 외부 입력의 Brotli 디코딩을 막거나 끄고 유료 연장 지원 빌드를 검토하세요.
브라우저도 영향을 받나요?
CVE 레코드와 이 글에서 인용한 권고문은 Brotli C 라이브러리와 이를 포함한 Node.js, Bun, Envoy, 파이썬 패키지 같은 프로젝트를 다룹니다. 브라우저를 언급한 곳은 없으니, 어느 쪽으로도 단정하지 말고 브라우저 제조사의 릴리스 노트를 확인하세요.
Node2Shell은 누가 발견했나요?
Node.js는 OpenAI Codex Security와 연구원 Khai Tran, Sylvie Mayer를 발견자로 밝혔습니다. 이후 Imperva가 이 버그에 Node2Shell이라는 이름을 붙이고 코드 실행을 시연했습니다.
출처
- Node.js: October 21, 2026 Security Releases
- CVE-2026-111497 레코드(cve.org)
- Google Brotli v1.2.1 릴리스
- Imperva: Node2Shell, From Brotli Data to Remote Code Execution
- Envoy 권고문 GHSA-3wvj-j6qm-62mr
- Bun v1.4.4 릴리스 노트
- 데비안 보안 트래커: CVE-2026-111497
- Sysdig: Detecting the Node.js Brotli RCE
- HeroDevs: CVE-2026-111497 (Node2Shell)
- expressjs/body-parser README
- PyPI: Brotli, PyPI: brotlicffi