Broccoli2Shell: Brotli decoder RCE (CVE-2026-111497) in Node.js, Python and more
Broccoli2Shell: Node.js·Python 등의 Brotli 디코더 원격 코드 실행 취약점 (CVE-2026-111497)
Brotli의 C 디코더가 잘못된 블록 전환을 처리하는 과정에서 버퍼를 넘겨 쓰는 취약점이 발견됐습니다. 공격자가 조작한 압축 데이터를 디코딩하는 Node.js와 Python 앱 등이 영향을 받으며, 수정된 런타임과 라이브러리로 올리고 관련 프로세스를 재시작해야 합니다.
- 주제
에디터 노트
실제 Node.js 24.22.0 공식 이미지에서 공격자 코드 실행에 성공했다는 Imperva의 결과가 있어 취약점의 영향을 단순한 이론으로 치부하기는 어렵습니다. 다만 성공에는 여러 시도가 필요했고, 공개 PoC가 표준 빌드에서 보여준 결과는 코드 실행이 아니라 충돌과 제한된 메모리 읽기라고 원문은 구분합니다. Reddit 댓글은 일부 PoC가 비현실적인 설정을 요구한다며 경보 수위에 의문을 제기하지만, 그 의견만으로 실제 앱 구성의 위험을 판정할 수는 없습니다. 취약 여부는 앱이 외부 응답이나 요청 본문 등 공격자가 제어하는 Brotli 데이터를 해당 C 디코더에 전달하는지에 달려 있습니다. 특히 Node.js는 시스템 라이브러리 업데이트가 런타임 내장 사본을 고치지 않으므로 런타임을 올려야 합니다.
AI 요약
Brotli C 디코더의 블록 전환 오류로 원격 코드 실행까지 이어질 수 있는 CVE-2026-111497 취약점이 발견됐습니다. 공격자가 제어하는 Brotli 데이터를 디코딩하는 앱이 대상입니다. Node.js의 fetch()는 Brotli 응답을 자동으로 풀고, Python의 requests·urllib3·aiohttp도 Brotli 패키지가 설치되면 응답을 디코딩할 수 있습니다. Express 5.0.0~5.3.0과 body-parser 2.0.0~2.3.0은 Brotli 요청 본문을 풀어 취약한 디코더로 전달하는 경로일 뿐, 자체적으로 취약한 코드를 포함하지 않습니다. Node.js 내장 HTTP 서버는 요청 본문을 자동 해제하지 않습니다.
취약점 원인과 영향
Brotli 스트림은 여러 블록으로 구성됩니다. 수정 전 디코더의 DecodeBlockTypeAndLength()는 잘못된 형식과 입력 부족을 구분하지 못하는 불리언 값을 반환했습니다. 빠른 처리 경로에서는 반환값도 확인하지 않았습니다. 공격자가 불가능한 블록 전환을 요청하면 디코더가 입력을 더 기다리는 것으로 오인해 8바이트 내부 버퍼에 데이터를 계속 추가하고, 버퍼 밖을 덮어씁니다. 그 결과 인접한 디코더 상태가 손상돼 메모리 노출이나 코드 실행으로 이어질 수 있습니다. upstream 수정은 BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH(-17)를 반환해 잘못된 형식을 명확히 거부합니다. 관련 분류는 CWE-252와 CWE-787입니다.
Node.js는 자체 Brotli 사본을 포함하므로 시스템의 libbrotli를 업데이트해도 Node.js 런타임은 고쳐지지 않습니다. 본문에 제시된 수정 버전은 Node.js 22.23.4, 24.22.1, 26.12.1입니다. Python의 PyPI 패키지 Brotli와 brotlicffi는 같은 C 디코더를 컴파일합니다. urllib3와 requests, aiohttp, httpx[brotli], Scrapy 등이 설치된 패키지를 자동으로 사용할 수 있어 앱 코드에서 직접 import하지 않아도 노출될 수 있습니다. 수정 버전은 Brotli 1.2.1 이상, brotlicffi 1.2.1.0 이상입니다. 배포판 패키지를 쓰는 경우에는 해당 Linux 배포판의 보안 업데이트를 확인해야 합니다.
다른 제품과 대응 방법
Brotli 1.0.3~1.2.0을 포함하거나 연결하는 소프트웨어도 점검 대상입니다. 본문은 .NET 런타임, PHP·Ruby 바인딩, DuckDB, ClickHouse, Apache Arrow, libjxl, 일부 아카이버와 펌웨어 도구 등 수정되지 않은 사본이 확인된 프로젝트를 열거합니다. 반면 Node.js, Bun, Chromium, Firefox, brotlicffi 등은 이미 수정됐다고 설명합니다. 정적 링크나 vendored 사본은 시스템 라이브러리 업데이트만으로 고쳐지지 않으므로 각 프로젝트의 수정판을 확인해야 합니다. 프로젝트 목록은 GitHub 코드 검색으로 확인한 결과라 완전하지 않으며, 실제 영향 여부는 제품 버전과 구성에 따라 달라질 수 있습니다.
운영 환경뿐 아니라 스테이징, CI 러너, 컨테이너 이미지, 서버리스 런타임과 개발자 장비까지 버전을 점검하고, 업그레이드 뒤에는 프로세스를 재시작하고 이미지를 다시 빌드해야 합니다. Python에서는 Brotli와 brotlicffi를 제거하면 일부 HTTP 클라이언트가 gzip이나 deflate로 대체할 수 있습니다. 요청 본문에서 Brotli를 차단하는 방법은 인바운드 경로에만 적용됩니다. 앱이 외부 URL을 가져오는 아웃바운드 경로는 런타임이나 라이브러리 업그레이드가 필요하며, Node.js에는 별도 우회책이 없다고 설명합니다.
공격 검증과 관련해서는 Imperva Red Team이 수정 전 Node.js 24.22.0 Linux arm64 공식 이미지에서 외부 코드 실행에 성공했고, 가져온 응답과 Express 요청 본문 두 경로를 시험했다고 밝혔습니다. 성공까지 여러 차례 시도했으며 익스플로잇은 공개하지 않았습니다. 공개 PoC는 일부러 약화한 빌드에서 코드 실행에 도달한다고 보고됐고, 표준 빌드에서는 충돌과 제한된 메모리 읽기가 확인됐다고 합니다. Python 연구진은 AddressSanitizer로 결함을 확인했지만 익스플로잇은 시도하지 않았습니다.
Reddit 반응
- @FIREstopdropandsave — 사기가 나아질 때까지 CVE는 계속될 겁니다.
- @yotemato — 제발 그만해 주세요. 이번 주 내내 치명적인 취약점 패치를 하고 있습니다.
- @nicofff — 실제 애플리케이션 구성에서 작동하는 모습을 보여준 사람이 있나요? RCE에 이상한 설정이 필요한 PoC 하나가 나올 때마다 사이버 보안 업체가 만든 AI 페이지 15개가 위험성을 외치는 것 같습니다.
- @VRT303 — PHP 쪽도 악용하려면 나쁜 관행이 많이 필요합니다. 인기 있는 PoC 중 쉽게 작동하는 것은 없습니다.
- @obetu5432 — NSA는 요즘 힘들겠네요. 최고의 백도어들이 패치되고 있으니까요.
- @SeaworthinessThat594 — 보스, 이제 지쳤습니다.
원문: broccoli2shell.com / 번역·요약: Trawling