Brotli CVE-2026-111497 (Node2Shell / HTTP2Shell): 영향을 받는 버전, 수정된 릴리스 및 해결 방법

CVE-2026-111497에서 발생한 일

CVE-2026-111497은 Google의 Brotli 디코더에서 발생하는 심각한 범위를 벗어난 쓰기(out-of-bounds write) 취약점으로, 모든 플랫폼의 Brotli 버전 1.0.3부터 1.2.0까지 존재합니다. Node.js는 2026년 10월 21일 주에 이를 "Node2Shell"로 공개했으며, 보안 연구원들이 동일한 디코더 버그가 Python 패키지, 네이티브 libbrotli, curl, Bun, Envoy, Istio, Git for Windows 및 Brotli 디코더를 번들하는 많은 애플리케이션에 영향을 미친다는 것을 확인하면서 이름은 "HTTP2Shell"로 확장되었습니다. 수정 사항은 Brotli 1.2.1(및 백포트 1.0.10 및 1.1.1)에 포함되어 있으며, 취약한 Brotli 디코더를 정적으로 링크하거나 번들하는 모든 라이브러리 또는 애플리케이션은 자체 릴리스가 필요합니다.

Aikido는 2026년 10월 23일에 통합 권고를 게시했으며, 패치가 여전히 생태계 전반에 걸쳐 배포 중이고 공급업체가 영향을 받는 구성 요소를 순차적으로 발표하고 있다고 언급했습니다.

기술적 근본 원인: DecodeBlockTypeAndLength()의 모호한 부울

결함은 Brotli 스트림이 사용하는 Huffman 트리를 변경하는 블록 전환을 처리하는 Brotli 디코더 함수인 DecodeBlockTypeAndLength()에 있습니다. 취약한 버전에서 이 함수는 일반 부울을 반환하므로 BROTLI_FALSE는 "이 스트림이 잘못되었습니다" 또는 "더 많은 입력이 필요합니다"를 의미할 수 있습니다. 호출자는 두 경우를 구분할 수 없으며, 빠른 디코딩 경로에서 디코더는 반환 값을 완전히 무시합니다.

조작된 스트림은 단일 블록 유형을 선언한 다음 해당 블록의 길이를 소진하여 성공할 수 없는 블록 전환을 강제할 수 있습니다. 그런 다음 디코더는 실제로 완료된 스트림에 대해 더 많은 입력이 필요하다고 보고하거나 이미 가지고 있던 블록 상태로 디코딩을 계속합니다. 두 번째 경로는 범위를 벗어난 쓰기를 생성합니다.

업스트림 수정 사항인 google/brotli 커밋 0ed4268은 함수가 오류 코드를 반환하도록 만들고 새로운 오류 값인 BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH(-17)를 도입합니다. 이제 디코딩은 안전 경로와 빠른 경로 모두에서 형식 오류 시 중지됩니다. Brotli 1.2.0 및 1.2.1 소스 배포판의 차등 분석 결과 1.2.1은 버전 범프와 해당 커밋의 디코더 변경 사항만 다릅니다.

CVE 레코드는 CWE-252(확인되지 않은 반환 값)와 CWE-787(범위를 벗어난 쓰기)을 쌍으로 지정하고 CVSS v4.0 점수 9.2(심각)를 할당합니다.

공격 영향: 메모리 누수, 충돌 또는 양방향 원격 코드 실행

CVE-2026-111497을 통해 원격의 인증되지 않은 공격자는 메모리를 손상시키고, 중요한 데이터를 유출하고, 프로세스를 충돌시키거나, 잠재적으로 임의 코드 실행을 달성할 수 있는 조작된 Brotli 압축 스트림을 보낼 수 있습니다. 이 결함은 양방향으로 작동하는 인증되지 않은 원격 코드 실행으로 보고되었습니다. 즉, 악성 클라이언트가 패치되지 않은 서버를 장악할 수 있고 악성 서버가 압축된 응답을 수락하는 패치되지 않은 클라이언트를 장악할 수 있습니다.

디코더를 노출시키는 두 가지 데이터 경로가 있습니다.

  • 아웃바운드 요청. 애플리케이션이 공격자가 제어하는 서버에서 Brotli로 인코딩된 응답을 가져옵니다(예: 웹훅 전달, URL 미리 보기, 크롤러 또는 "이 URL 가져오기" 기능).
  • 인바운드 요청. 프레임워크 또는 미들웨어가 Content-Encoding: br로 전송된 요청 본문을 디코딩합니다. 이는 Node.js의 Express 5 사례에 해당하는 Python입니다.

The Hacker News는 2026년 10월 22일 현재 야생에서의 악용이 없다고 보도했습니다.

CVE-2026-111497에 대한 수정된 버전

Brotli를 번들하는 모든 프로젝트는 자체 업데이트를 제공해야 합니다. 근본 원인이 소스에서 업스트림으로 수정되었지만 지금까지 수정 사항을 제공한 업스트림 릴리스가 없었기 때문입니다. 2026년 10월 23일에 검토된 수정 릴리스:

프로젝트 패치 상태 수정된 버전 참고
Node.js 패치 사용 가능 22.23.4, 24.22.1, 26.12.1 지원되는 릴리스 라인 사용
Bun 패치 사용 가능 1.4.4 Brotli 1.2.1 포함
Envoy 패치 사용 가능 1.40.0, 1.39.3, 1.38.6, 1.37.8 1.36.12에도 수정 사항이 포함되어 있지만 1.36은 지원되지 않음
Istio 패치 사용 가능 1.29.9, 1.30.6, 1.31.2 1.29는 수명 종료, 지원되는 라인으로 이동
Google Brotli (업스트림) 패치 사용 가능 1.0.10, 1.1.1, 1.2.1 해당 라이브러리 분기에 맞는 수정 릴리스 선택
Python: Brotli (PyPI) 패치 사용 가능 1.2.1 릴리스 노트에 CVE 언급 없음
Python: brotlicffi (PyPI) 패치 사용 가능 1.2.1.0 릴리스 노트에 CVE 언급 없음

권고의 추가 지침:

  • curl / libcurl: Brotli 종속성을 1.2.1, 패치된 이전 릴리스 또는 공급업체의 보안 수정 패키지로 업데이트합니다. 번들되거나 정적으로 링크된 복사본은 업데이트된 애플리케이션 빌드가 필요합니다.
  • 운영 체제 패키지: 공급업체의 보안 업데이트를 설치합니다. 공급업체는 업스트림 버전 번호를 변경하지 않고 수정 사항을 백포트할 수 있습니다.
  • 기타 HTTP 서버, 리버스 프록시, API 게이트웨이 및 HTTP 클라이언트: 영향을 받는 런타임 또는 사용하는 Brotli 라이브러리를 업데이트합니다. Brotli가 제품에 번들된 경우 이 CVE를 명시적으로 해결하는 제품 공급업체의 릴리스를 설치합니다. 관리형 서비스의 경우 공급자에게 해결 방법을 확인합니다.

업그레이드 후 종속성 잠금을 업데이트하고, 영향을 받는 애플리케이션과 컨테이너 이미지를 다시 빌드하고, 재배포하고, 서비스를 다시 시작한 다음 실행 중인 워크로드가 패치된 구성 요소를 사용하는지 확인합니다.

하나의 Brotli 버그가 많은 언어와 제품에 영향을 미치는 이유

Python, Node.js, C++, libbrotli, Envoy 및 Bun은 모두 동일한 C Brotli 디코더를 컴파일하거나 번들하기 때문에 영향을 받습니다. 디코딩 로직의 구현은 하나뿐이므로 단일 메모리 안전 결함이 이를 포함하는 모든 런타임으로 전파됩니다.

두 PyPI 패키지인 Brotli와 brotlicffi는 Node.js가 번들하는 것과 동일한 취약한 디코더를 컴파일하며, Brotli는 월 8,280만 건의 다운로드를 기록합니다. urllib3(따라서 requests), brotli 추가 기능이 있는 httpx, aiohttp와 같은 HTTP 클라이언트는 패키지가 존재할 때 자동으로 로드하고 애플리케이션이 Brotli를 직접 가져오지 않고도 Brotli 응답을 디코딩합니다. Scrapy 및 기타 패키지는 Brotli를 종속성으로 설치합니다. 결과적으로 Python 애플리케이션은 자체 소스 코드에 Brotli 가져오기가 하나도 없어도 노출될 수 있습니다.

일부 구성 요소는 디코딩 경로에 취약하지 않습니다. Apache의 표준 mod_brotli는 Brotli를 디코딩하지 않으며 Apache와 Nginx는 기본적으로 Brotli를 디코딩하지 않습니다.

권고 데이터베이스 격차: pip-audit, Dependabot 및 Safety는 아직 이를 플래그하지 않습니다.

2026년 10월 23일 현재 권고 데이터베이스는 CVE-2026-111497을 Brotli 또는 brotlicffi PyPI 패키지에 매핑하지 않았습니다. CVE 레코드, OSV 및 GitHub Advisory Database는 두 패키지를 나열하지 않았으며, 이는 pip-audit, Dependabot 및 Safety가 취약한 버전을 플래그하지 않음을 의미합니다. GitHub 권고가 GHSA-9v8h-qqgm-4m35에 게시되었으며, 보고자는 도구가 이를 인식할 수 있도록 PYSEC 항목과 GitHub 권고에 대한 PyPI 패키지 매핑을 제출하고 있었습니다. 해당 매핑이 이루어질 때까지 노출 확인은 수동으로 수행해야 합니다.

애플리케이션이 노출되었는지 확인하는 방법

취약한 Brotli 디코더의 설치된 복사본만으로도 애플리케이션 코드가 호출하지 않더라도 노출될 수 있습니다. 실용적인 확인 방법:

  1. 각 환경에서 pip show Brotli brotlicffi로 설치된 버전을 확인하고 각 컨테이너 이미지에 대해 docker run --rm <image> pip show Brotli brotlicffi로 확인합니다.
  2. 패키지를 가져오는 항목을 찾습니다. pipdeptree -r -p Brotli를 실행하여 어떤 종속성이 필요한지 확인하고 grep -i brotli poetry.lock uv.lock requirements*.txt로 잠금 파일을 검색합니다.
  3. 제어하지 않는 서버로 가는 아웃바운드 HTTP 호출과 Content-Encoding: br 요청 본문을 디코딩하는 모든 엔드포인트를 나열합니다.
  4. 3단계와 일치하는 서비스를 먼저 업그레이드한 다음 나머지를 업그레이드합니다.

재현 작업의 경우: brotli.decompress()는 모든 오류에 대해 일반적인 brotli.error: decoder failed를 발생시키므로 특정 오류 코드는 Python에서 볼 수 없습니다. 조작된 스트림을 점진적으로 공급하는 Decompressor()는 1.2.0에서 완료되지 않습니다. AddressSanitizer로 빌드된 Brotli 1.2.0 및 1.2.1을 테스트한 결과 1.2.0은 스트림이 한 번에 도착하든 1바이트 크기의 청크로 도착하든 관계없이 더 많은 입력이 필요하다고 반복적으로 보고하면서 약 23MB의 조작된 스트림을 모두 소비했습니다. 버전 1.2.1은 오류 -17로 스트림을 매번 거부했습니다.

즉시 업그레이드할 수 없는 경우의 해결 방법

이러한 완화 조치는 패치가 준비되는 동안 노출을 줄입니다.

  • Python 애플리케이션: Brotli 지원이 선택 사항인 경우 영향을 받는 환경에서 Brotli와 brotlicffi를 모두 제거합니다. httpx[brotli]와 같은 종속성 추가 기능 및 이를 다시 설치할 수 있는 기타 요구 사항을 제거한 다음 종속성 잠금을 다시 생성하고 워크로드를 다시 빌드하거나 다시 시작합니다. httpx, requests 및 urllib3는 선택적 패키지 없이도 gzip 및 deflate 지원을 유지하지만, 어쨌든 Brotli를 보내는 서버는 읽을 수 없는 응답이나 애플리케이션 오류를 생성할 수 있으며 자동 폴백은 보장되지 않습니다.
  • 들어오는 HTTP 요청: 취약한 디코더가 본문을 처리하기 전에 리버스 프록시, 로드 밸런서 또는 애플리케이션 미들웨어에서 Content-Encoding에 br이 포함된 요청을 거부합니다. 인코딩 목록 내에 나타날 때를 포함하여 br을 대소문자를 구분하지 않고 일치시킵니다.
  • 나가는 HTTP 요청: Accept-Encoding에서 br을 제거하고 Brotli 응답 디코딩을 비활성화하거나 디코딩이 시작되기 전에 Content-Encoding에 br이 포함된 응답을 거부합니다. 확인은 자동 본문 처리 전에 이루어져야 합니다. 클라이언트가 응답을 다운로드하고 디코딩한 후 확인하는 것은 너무 늦습니다.

Accept-Encoding만 변경하는 것으로는 충분하지 않습니다. 악성 서버는 클라이언트가 광고하는 내용과 관계없이 Brotli 응답을 보낼 수 있고 urllib3는 응답의 Content-Encoding 헤더에서 디코더를 선택하기 때문입니다. Python 패키지를 제거해도 다른 런타임, 라이브러리 또는 제품에 번들된 별도의 Brotli 디코더는 제거되지 않습니다.

공개 타임라인 및 OpenAI 2월 발견

Aikido의 TL;DR은 Node.js가 2026년 10월 21일 수요일에 CVE-2026-111497을 공개했다고 명시하는 반면, 동일한 권고의 이후 타임라인 섹션은 Node.js 공개를 2026년 10월 22일 수요일로 설명합니다. 소스에는 두 날짜가 모두 나열됩니다. Python은 다음 날 동일한 결함을 패치하는 보안 업데이트를 게시했습니다. 10월 23일 금요일에는 CVE가 HTTP를 사용하는 다른 주요 언어 및 서비스 애플리케이션에 영향을 미치며 패치가 아직 완전히 제공되지 않은 것으로 알려졌습니다.

OpenAI는 2월에 취약점을 발견했다고 밝혔습니다. 근본 원인은 당시 Brotli 소스 코드에서 수정되었지만 보안 문제로 인식되지 않았고 2026년 10월까지 수정 사항이 포함된 릴리스가 제공되지 않았습니다. OpenAI는 이를 양방향으로 작동하는 인증되지 않은 원격 코드 실행으로 보고했으며 patchtheplanet.org/brotli에서 참조되는 권고를 게시했습니다.

Hacker News 댓글 작성자들은 귀속에 대해 반박했습니다. 한 댓글 작성자는 2월 변경이 OpenAI가 아닌 Google에서 나왔다고 주장했습니다.

기사는 OpenAI가 2월에 이것을 발견했다고 주장하지만, 그것이 정확하다고 생각하지 않습니다. Google이 2월에 Brotli 소스 코드를 변경하여 문제를 수정했지만 보안 문제임을 인식하지 못해 릴리스를 내놓지 않았다고 생각합니다.

또 다른 댓글 작성자는 심각도 보고와 릴리스 제공 사이의 격차를 강조했습니다.

양방향으로 작동하는 인증되지 않은 원격 코드 실행으로 보고했지만 ... 당시에는 보안 문제로 인식되지 않았고 지금까지 수정 사항이 포함된 릴리스가 제공되지 않았습니다. 저는 항상 위험한 RCE 버그와 무해한 RCE 버그를 혼동합니다. 2월에 이것이 어떻게 보고되고 수정되었지만 아무도 중요성을 인식하지 못했는지 궁금합니다. AI 자동화의 사례이고 아무도 운전대를 잡지 않은 경우입니까?

커뮤니티 반응: 명명, 복잡성 및 C 언어 논쟁

Hacker News 토론에서 가장 일관된 불만은 이름이었습니다. Python 및 기타 생태계가 영향을 받는 것으로 확인되자 "Node2Shell"은 더 이상 범위를 설명하지 못했고 "HTTP2Shell"은 너무 광범위하고 모호하다는 이유로 널리 거부되었습니다.

글쎄요, HTTP2Shell이라는 이름을 선택한 사람은 확실히 지능(인공적이든 진짜든)을 사용하지 않았습니다. 너무 무의미하고 광범위하며 실제 문제를 설명하지 못합니다. 아니요, 뒤에 아무것도 없는 HTTP 서버에는 영향을 미치지 않을 것이므로 HTTP가 왜 비난을 받는 것입니까?

스레드에서 제안된 대체 이름에는 Brotli2Shell과 Broccoli2Shell이 포함되었습니다. 한 댓글 작성자는 HTTP가 버그와 관련이 없을 뿐이라고 주장했습니다.

같은 취약점에 대해 Broccoli2Shell 이름과 사이트를 훨씬 선호합니다. 우선 HTTP 없이 수동으로 Brotli 디코딩을 수행하면 이 문제가 발생할 수 있다고 확신합니다. HTTP는 가장 일반적인 경우일 뿐입니다.

여러 댓글 작성자는 기본 구성에서 Brotli 압축 요청 본문이 실제로 얼마나 널리 디코딩되는지 의문을 제기하며 권고가 일반적인 응답 압축 해제와 더 모호한 인바운드 경로 사이의 차이를 흐리게 했다고 주장했습니다.

저에게 놀라운 점은 얼마나 많은 구현이 요청(응답이 아닌) 본문의 brotli 압축을 구현하는지입니다. 그 기능이 얼마나 생소한지 고려할 때 말이죠. 어쨌든 이런 선정주의는 점점 짜증나기 시작합니다. 패치하고 넘어가세요.

복잡성 논쟁도 표면화되었으며, gzip/deflate를 대체하는 비용으로 프레임되었습니다.

추가된 복잡성의 비용의 예라고 생각합니다. Brotli는 대체하는 gzip/deflate보다 훨씬 복잡합니다. ... 그리고 물론 우리는 여전히 gzip을 공격에 노출해야 합니다. 무언가를 추가할 때마다 무언가를 잃습니다...

한 스레드는 이것이 C에 대한 반대 논거인지에 대해 회전했습니다.

솔직히 이제 보안이 중요한 곳에서 사용되는 언어로 C를 제거할 때입니다. 충분합니다. 공개 인터넷 트래픽을 처리하고 Google이 유지 관리하는 brotli와 같은 라이브러리가 왜 rust가 아닌가요?

업스트림 패치의 검토자는 서두르는 것 같다고 생각했습니다.

C 코드 패치를 읽어봤습니다(그런데 isSafe? 메서드 등이 추가된 것이 저에게는 약간 해킹처럼 보입니다 ... 이 패치는 "버퍼 오버플로우 C 돼지에 립스틱"처럼 보입니다). ... Python / Node / C++ / libbrotli / Envoy / Bun 사이의 연관성은 무엇입니까? 모두 동일한 C brotli 인코더/디코더를 사용합니까?

그 댓글 작성자의 질문에 대한 답은 예입니다. 모두 동일한 Brotli C 디코더를 포함하거나 링크하므로 업스트림 Brotli 1.2.1만으로는 자체 복사본을 번들하는 시스템을 보호할 수 없습니다.

댓글 작성자가 보고한 운영상 영향을 받는 소프트웨어

댓글 작성자들은 권고 표를 넘어 실제 노출을 목록화했습니다.

  • Git for Windows는 최신 릴리스(2.56.0.windows.3)에서도 취약합니다. 수정 사항은 저장소에 병합되었지만 스냅샷 빌드에서만 사용할 수 있으며 후속 릴리스는 월요일(2.56.0.windows.4)에 예상됩니다. 신뢰할 수 없는 서버에서 HTTPS를 통해 저장소를 가져오는 것이 관련 위험입니다.
  • Codex(GUI)는 자체 Git과 자체 Node를 제공하며, 댓글 작성자들은 잠재적으로 더 높은 위험으로 설명했습니다. 제안된 완화 조치는 Codex를 업데이트하고 ~/.cache/codex-runtimes에서 캐시를 지우는 것입니다.
  • Wireshark와 ImHex는 최신 저장소 커밋에서도 여전히 취약합니다.
  • Microsoft 365 Copilot은 여전히 10월 7일자 자체 패치되지 않은 brotlidec.dll을 제공했으며, 수정 사항이 없고 취약한 디코더에 도달할 수 있는 확인된 경로가 없습니다.
  • Ubuntu는 여전히 libbrotli1 패치를 중간 심각도 항목으로 검토 중이었으며, 이로 인해 libcurl 및 따라서 Git 및 기타 종속 패키지에 대한 업데이트가 보류되었습니다.
  • 단일 Windows 개발 상자에서 파일 검색 결과 Brotli 라이브러리가 Git, Sublime Text, Visual Studio, CUDA, .NET, Inkscape 및 Azure Tools에 링크되어 있음을 발견했습니다.

한 운영 측 댓글 작성자는 자사 환경을 확인하고 노출이 전혀 없음을 발견하여 전이적 종속성 복권을 보여주었습니다.

모든 Python 배포와 설치 BOM을 확인해야 했고 매우 안도했습니다. 실제로 아무도 brotli 라이브러리를 설치하지 않았습니다. httpx, requests와 같은 HTTP 라이브러리와 프레임워크는 이를 선택 사항으로 간주하고 존재를 자동 감지합니다.

스레드에서 제기된 답이 없는 아키텍처 질문은 로드 밸런서가 TLS를 종료하고 압축 해제를 처리할 때 애플리케이션이 안전한지 여부였습니다.

TLS를 종료하는 Amazon Elastic Load Balancer 뒤에 node.js 앱이 있다고 가정해 보겠습니다. 제 이해로는 거의 모든 구성에서 ELB가 압축 해제를 처리하므로 앱은 영향을 받지 않을 것입니다. 일반적으로 맞습니까?

토론에는 확실한 답변이 기록되어 있지 않으므로 실용적인 규칙은 에지 프록시가 위험을 제거한다고 가정하지 말고 디코딩 경로의 모든 구성 요소를 감사하는 것입니다.

패치 속도 문제

토론은 또한 종속성 관리의 더 넓은 긴장을 포착했습니다. 패키지 생태계는 2025년 내내 엔지니어들에게 공급망 공격을 피하기 위해 새로 게시된 릴리스에 쿨다운을 적용하라고 조언했으며, 이제 중요한 취약점으로 인해 이러한 쿨다운이 무시되고 있습니다.

몇 달 전만 해도 모든 사람이 패키지 업그레이드에 쿨다운을 사용하라고 조언했습니다. 이제 보안 사고가 즉시 악용될 것이기 때문에 우리는 계속해서 이를 무시하고 있습니다. 이제부터는 그렇게 될 것 같습니다.

일부 엔지니어는 자동화된 수정으로 대응했으며, 한 댓글 작성자는 새로운 권고가 나타날 때마다 Claude Code를 지적하는 것으로 설명했습니다. 다른 사람들은 실용적인 자세를 직설적으로 표현했습니다. 패치하고, 다시 빌드하고, 재배포하고, 넘어가십시오. 스레드가 이의를 제기하지 않은 한 가지 점은 Brotli 디코더가 이제 거의 모든 HTTP 클라이언트와 서버의 신뢰할 수 없는 입력 공격 표면의 일부이며 Brotli를 번들하는 모든 프로젝트는 CVE-2026-111497에 대한 자체 업데이트를 제공해야 한다는 것입니다.

Sources

관련

  • Dispatch
  • 프로젝트
  • 프로젝트
  • Dispatch
  • Dispatch