
CVE-2026-111497의 영향을 받는 Brotli 디코더(libbrotlidec, Node.js, Python, .NET)에 대해 Linux 호스트를 감사하는 Checkmk 확장으로, 버전, 백포트 및 오래된 프로세스를 확인합니다.
Linux 호스트의 모든 Brotli 디코더에 대해 Broccoli2Shell - CVE-2026-111497 - 의 영향을 받는지 여부를 보여주는 Checkmk 확장입니다. 이 취약점은 Google의 C Brotli 디코더에서 발생하는 범위를 벗어난 쓰기(out-of-bounds write)로, 프로그램이 신뢰할 수 없는 출처(HTTP 응답, 요청 본문, 아카이브)의 Brotli 데이터를 압축 해제할 때 원격 코드 실행으로 이어질 수 있습니다. 이 취약점은 2026-10-21/22에 공개되었으며 Brotli 1.0.10, 1.1.1, 1.2.1, Node.js 22.23.4, 24.22.1, 26.12.1, Python 패키지 Brotli 1.2.1 및 brotlicffi 1.2.1.0, 그리고 .NET 8.0.33, 9.0.22, 10.0.14에서 수정되었습니다.
이 확장은 사실만 수집하는 작은 POSIX 셸 에이전트 플러그인을 제공합니다(시스템 라이브러리 libbrotlidec, Node.js 바이너리, Python Brotli 및 brotlicffi 설치, .NET 런타임, 해당 버전, 패키지 체인지로그, 이들이 링크된 대상, 이를 로드한 프로세스, 그리고 교체된 버전을 여전히 실행 중인 프로세스). "수정됨"인지 "취약함"인지는 Checkmk 서버의 체크 플러그인이 결정하므로, 새로운 정보(또 다른 수정 릴리스)가 있을 때 모든 호스트에 새 스크립트를 배포할 필요 없이 업데이트된 .mkp만 있으면 됩니다.
단순히 버전 번호만 비교하지 않는 이유: 배포판은 업스트림 버전을 변경하지 않고 수정 사항을 백포트하며, Node.js가 번들로 포함한 사본 대신 시스템 라이브러리에 대해 Node.js를 빌드합니다. Debian 12는 libbrotli 1.0.9와 Node.js 18.20.4(업스트림 수명 종료, 수정 없음)를 제공하지만, 둘 다 수정된 상태입니다. 업데이트된 libbrotli1 패키지가 바로 Node.js가 실행하는 디코더이기 때문입니다. 따라서 이 확장은 각 디코더를 소유한 패키지의 체인지로그를 읽고, Node.js 및 Python 확장이 링크된 라이브러리를 추적합니다.
cmk_addons.plugins 플러그인 API 사용)./proc/<pid>/maps를 읽음). GNU 또는 busybox 도구가 있는 순수 POSIX sh; 패키지 체인지로그는 dpkg, rpm 또는 apk로 읽음. Debian 계열, Red Hat 계열, Amazon Linux 및 Alpine에서 테스트되었으며 아래를 참조.| Checkmk 이미지 | 날짜 | 결과 |
|---|---|---|
checkmk/check-mk-ultimate:2.5.0p17 | 2026-10-28 | OK (빌드, cmk-validate-plugins, 스모크 테스트, 설치 + 검색 + 체크 + 에이전트 베이크) |
checkmk/check-mk-ultimate:3.0.0-2026.10.28 (daily) | 2026-10-28 | OK (빌드, cmk-validate-plugins, 스모크 테스트, 설치 + 검색 + 체크 + 에이전트 베이크) |
에이전트 플러그인은 2026-10-28에 배포판 자체 패키지와 공식 이미지에 대해 실행되었으며(scripts/test_agent_plugin.sh), 디코더를 로드한 node 및 python 프로세스와 함께 테스트되었습니다. 이후 라이브러리, node 바이너리 및 Python 확장 모듈이 디스크에서 교체되었고, 재시작 감지가 실행 중인 프로세스를 보고했습니다.
배포판
| 배포판 | 디코더 | 플러그인 결과 |
|---|---|---|
| Debian 12 | libbrotli 1.0.9-2+deb12u1, Node.js 18.20.4 (연결됨), python3-brotli | 백포트로 수정됨 (changelog), Node.js는 라이브러리를 통해 |
| Debian 13 | libbrotli 1.1.0-2+deb13u1, Node.js 20.19.2 (연결됨), python3-brotli, python3-brotlicffi (연결됨) | 백포트로 수정됨, Node.js와 brotlicffi는 라이브러리를 통해 |
| Ubuntu 24.04 | libbrotli 1.1.0-2ubuntu0.1, Node.js 18.19.1 (연결됨), python3-brotli, dotnet-runtime-8.0 8.0.32 | 백포트로 수정됨 - .NET 취약함 (8.0.33은 아직 아카이브에 없음) |
| AlmaLinux 8.10 | libbrotli 1.0.6-5.el8_10, Node.js 10.24.0 (자체 디코더), python3-brotli | 라이브러리와 Brotli는 백포트로 수정됨 - Node.js 10 취약함 (수명 종료, 자체 디코더) |
| AlmaLinux 9.8 | libbrotli 1.0.9-10.el9_8.1, Node.js 16.20.2 (연결됨), python3-brotli, dotnet-runtime-8.0 8.0.32 | 백포트로 수정됨 - .NET 취약함 |
| AlmaLinux 10.2 | libbrotli 1.1.0-8.el10_2.1, Node.js 22.23.2 (연결됨), python3-brotli | 백포트로 수정됨 |
| Fedora 44 | libbrotli 1.2.1, Node.js 22.23.1 (연결됨), python3-brotli 1.2.1 | 버전으로 수정됨 |
| Amazon Linux 2023 | libbrotli 1.1.0-1.amzn2023.0.1, Node.js 18.20.8 (연결됨) | 취약함 - 아직 수정된 패키지 없음, Node.js는 라이브러리를 통해 |
| Alpine 3.22 | brotli-libs 1.1.1, Node.js 22.23.4 (연결됨), py3-brotli 1.1.1 | 버전으로 수정됨 |
공식 이미지 및 PyPI
| 이미지 | 디코더 | 플러그인 결과 |
|---|---|---|
node:24.22.0-slim | Node.js 24.22.0 (자체 디코더) | 취약함 |
node:24.22.1-slim | Node.js 24.22.1 (자체 디코더) | 버전으로 수정됨 |
node:20-alpine | Node.js 20.20.2 (자체 디코더) | 취약함 - 수명 종료, 수정 없음 |
node:24.22.0-slim, 바이너리가 /home/dev/.nvm/...로 이동됨 (사용자 소유) | Node.js 24.22.0 | 취약함 - 바이너리에서 버전을 읽음, 실행되지 않음 |
python:3.12-slim + pip install Brotli==1.2.0 brotlicffi==1.2.0.0, /srv/app/venv에 Brotli 1.1.0이 있는 venv | Brotli, brotlicffi (자체 디코더) | 취약함 (실행 중인 프로세스를 통해 발견된 venv) |
python:3.12-slim + 현재 PyPI | Brotli 1.2.1, brotlicffi 1.2.1.0 | 버전으로 수정됨 |
mcr.microsoft.com/dotnet/runtime:8.0.32 / :8.0 | .NET 8.0.32 / 8.0.33 | 취약함 / 버전으로 수정됨 |
Checkmk 사이트 자체(2.5.0p17)는 Python에 Brotli 패키지를 포함하지 않습니다. 플러그인은 아직 컨테이너 외부의 프로덕션 호스트에서 실행되지 않았습니다 - 특히 SELinux가 enforcing인 상태(RHEL 계열)에서는 실행되지 않았습니다. 해당 환경에서는 에이전트가 보통 unconfined로 실행됩니다.
Setup > Maintenance > Extension packages > Upload package, 또는 사이트 내부의 명령줄에서:
mkp add broccoli2shell-<version>.mkp
mkp enable broccoli2shell <version>
점검하려는 호스트에 에이전트 플러그인을 배포합니다:
호스트에서 서비스 검색을 실행합니다. 각 디코더마다 자체 서비스가 생성되며, 호스트당
하나의 Broccoli2Shell restart 서비스가 추가됩니다.
선택 사항: Setup > Services > Service monitoring rules > Broccoli2Shell (CVE-2026-111497) 및 Broccoli2Shell restart에서 상태를 조정합니다.
package/agents/plugins/broccoli2shell을 에이전트의 플러그인 디렉터리 아래
캐시 간격(cache-interval) 하위 디렉터리에 복사하고 실행 가능하게 만듭니다:
install -m 755 broccoli2shell /usr/lib/check_mk_agent/plugins/3600/broccoli2shell
3600 디렉터리는 에이전트가 이를 백그라운드에서 한 시간에 한 번 실행하고 그 사이에는 캐시된 결과를 제공하도록 합니다. 이를 plugins/에 직접 넣지 마십시오. 이는 대용량 바이너리와 모든 프로세스의 메모리 맵을 읽기 때문에 모든 에이전트 쿼리에 너무 많은 부담을 줍니다.
| 서비스 | 단위 | 상태 (기본값, 구성 가능) |
|---|---|---|
Broccoli2Shell <path> | 디코더, 예: Broccoli2Shell /usr/lib/x86_64-linux-gnu/libbrotlidec.so.1, Broccoli2Shell /usr/bin/node, Broccoli2Shell /usr/lib/python3/dist-packages (brotli), Broccoli2Shell /usr/lib/dotnet (.NET 8.0) | OK 수정됨 또는 영향 없음 - CRIT 취약함, 실행 중인 프로세스에 의해 로드됨 - CRIT 취약함, 로드되지 않음 - UNKNOWN 버전 또는 링크된 라이브러리를 확인할 수 없음 |
Broccoli2Shell restart | 디코더가 있는 호스트 | OK - CRIT 프로세스가 여전히 교체된 디코더를 사용 중 |
스크린샷은 Checkmk 2.5.0p17 테스트 사이트에서 가져온 것으로, 네 개의 호스트가 실제 에이전트 대신 sample-data/의 기록을 받습니다(실제 호스트 없음). Debian 12와 Ubuntu 24.04는 백포트로 수정되었으며, Node.js는 시스템 라이브러리를 통해 수정되었지만 Ubuntu에서는 .NET 8.0.32가 취약합니다. Amazon Linux 2023은 라이브러리가 아직 수정되지 않아 Node.js도 마찬가지입니다. 그리고 PyPI의 Brotli와 brotlicffi를 사용하는 Python 애플리케이션이 있습니다. 이들 모두 여전히 교체된 디코더를 실행하는 프로세스를 가지고 있습니다.

서비스의 세부 정보에는 다음 단계, 패키지, 해당 변경 로그의 내용, 그리고 링크된 라이브러리가 명시됩니다:

flowchart TD
A[Decoder] --> L{"Linked against the<br/>system libbrotlidec?"}
L -- "yes (distribution Node.js,<br/>Debian's brotlicffi)" --> LIB[result of that library's service]
L -- "not found" --> U[UNKNOWN]
L -- no --> B{Version known?}
B -- no --> U
B -- yes --> C{"Version >= fix of its branch?<br/>libbrotli/Brotli 1.0.10 / 1.1.1 / 1.2.1<br/>brotlicffi 1.2.1.0<br/>Node.js 22.23.4 / 24.22.1 / 26.12.1<br/>.NET 8.0.33 / 9.0.22 / 10.0.14<br/>or a newer branch"}
C -- yes --> OK[OK: fixed]
C -- no --> D{"Package changelog names<br/>CVE-2026-111497?"}
D -- yes --> OKB[OK: fixed by distribution backport]
D -- no --> E{"Loaded by a running process?"}
E -- yes --> CR[CRIT: vulnerable]
E -- no --> CR2["CRIT: vulnerable<br/>(own state in the rule)"]