메뉴 닫기

Node.js 보안 업데이트(2026년 10월) – Brotli 원격 코드 실행 취약점

 

    앞서 3줄 요약

  • 2026년 10월 21일 Node.js가 22.x, 24.x, 26.x 전 라인에 보안 업데이트를 배포했습니다. 수정된 취약점은 10건이고 그중 4건이 High 등급입니다.
  • 핵심은 Brotli 압축 해제 과정의 메모리 오류(CVE-2026-111497, 별칭 Node2Shell)입니다. 공개 PoC가 나왔고, 10월 27일 미국 CISA가 실제 악용 취약점(KEV) 목록에 올렸습니다.
  • 설정으로 막는 방법은 없습니다. 20이하는 버전을 올려야하며, 22.23.4 / 24.22.1 / 26.12.1 이상으로 업데이트하고 서비스를 재시작해야 합니다.

지금까지의 진행 상황 (10월 29일 기준)

패치 공개 일주일 만에 PoC 공개, 실제 공격 관측, CISA KEV 등재까지 이어졌습니다. 아직 패치하지 않았다면 우선순위를 가장 높게 잡아야 하는 상황입니다.

날짜 내용
10월 27일 CISA, 실제 악용 근거로 KEV 목록에 등재 (미 연방기관 조치 기한 11월 10일)
10월 26일 보안업체 ELLIO, 공개 익스플로잇을 담은 실제 공격 트래픽 관측 보고
10월 25일 Microsoft, .NET용 보안 업데이트 별도 배포
10월 22일 Google, CVE 레코드 공개 (CVSS 4.0 기준 9.2). Imperva, 공식 Node.js 24.22.0 이미지에서 원격 코드 실행 시연. GitHub에 PoC 공개
10월 21일 Node.js 22.23.4 / 24.22.1 / 26.12.1 배포, Google Brotli 1.0.10 / 1.1.1 / 1.2.1 배포

공개 PoC 상당수는 일반 빌드에서는 프로세스 충돌(서비스 중단)에 그치고, 보안 기능을 약하게 만든 환경에서만 코드 실행에 성공했다는 분석도 있습니다. 다만 충돌만으로도 서비스 장애가 나므로 위험도를 낮춰 볼 이유는 되지 않습니다.

영향 버전과 수정 버전

지원 중인 모든 라인이 영향을 받으며, 지원이 끝난(EOL) 버전은 패치 자체가 나오지 않습니다. Node.js 공식 공지에 따르면 보안 릴리스가 나올 때 EOL 버전은 항상 영향을 받는 것으로 봐야 합니다.

릴리스 라인 상태 (2026-10-21 기준) 수정 버전
Node.js 26 Current (10월 28일 LTS 전환 예정) 26.12.1 이상
Node.js 24 (Krypton) LTS 24.22.1 이상
Node.js 22 (Jod) Maintenance LTS (2027년 4월 30일까지) 22.23.4 이상
Node.js 25, 23, 21 EOL 패치 없음
Node.js 20 이하 EOL (20은 2026년 4월 30일 종료) 패치 없음 → 22 또는 24로 이전

Node.js 20 이하를 쓰고 있다면 이번 취약점이 그대로 남아 있는 상태이므로, 버전 업그레이드 계획을 바로 잡는 것이 좋습니다.

주요 취약점

핵심은 CVE-2026-111497입니다. Node.js에 내장된 Brotli 디코더가 조작된 압축 데이터를 거부하지 못해 내부 버퍼 바깥에 쓰기가 발생하고, 그 결과 프로세스 충돌·메모리 노출·원격 코드 실행으로 이어질 수 있습니다. 버그는 Node.js 자체 코드가 아니라 번들된 Google Brotli 라이브러리에 있습니다.

특히 아래 환경은 우선 패치 대상입니다.

  • Express 5.0.0~5.3.0, body-parser 2.0.0~2.3.0으로 Content-Encoding: br 요청 본문을 받는 API 서버 (자동으로 압축을 풀어 줌)
  • 외부 서버 응답을 받아 처리하는 프록시·크롤러·웹훅 처리기
  • 내장 fetch()로 외부 URL을 호출하는 서비스 (HTTPS 요청 시 기본으로 Brotli 응답을 요청함)

반대로 Node.js 기본 HTTP 서버는 요청을 받는 것만으로 Brotli를 풀지 않습니다. 취약 버전이 깔려 있어도, 외부에서 온 Brotli 데이터를 푸는 경로가 없으면 실제 노출은 아닙니다. 또 이 취약점은 런타임에 있으므로 Express 같은 npm 패키지만 올려서는 해결되지 않습니다.

CVE 등급 내용 영향 라인
CVE-2026-111497 High Brotli 디코더 범위 밖 쓰기, 원격 코드 실행 가능 22, 24, 26
CVE-2026-105482 High dns.resolve가 NUL 문자에서 이름을 잘라 허용 목록 검사 우회 22, 24, 26
CVE-2026-106069 High 0127.0.0.1 같은 비정규 IP 표기로 TLS 호스트명 검증 우회 22, 24, 26
CVE-2026-105483 High 전각 숫자 IP 표기로 TLS 호스트명 검증 우회 24, 26
CVE-2026-106072 Medium IP 접속 시 인증서의 DNS 이름을 잘못 허용 22, 24, 26
CVE-2026-105481 Medium Keep-alive 소켓이 요청 전에 온 응답을 받아들임 22, 24, 26
CVE-2026-106074 Medium 스냅샷·단일 실행 파일(SEA)에서 난수 값 반복 22, 24, 26
CVE-2026-106070 Low 실험 API ZipFile의 잘못된 바이트 반환 26
CVE-2026-106071 Low Permission Model 와일드카드 경로 과다 허용 26
CVE-2026-106073 Low fs.realpathSync로 Permission Model 우회 22, 24, 26

함께 OpenSSL 3.5.9, c-ares 1.34.9, Undici, 루트 인증서(침해된 eMudhra 중간 인증서 차단)도 업데이트됐습니다. 점수는 출처마다 다릅니다. Node.js는 High로 분류했고, Google이 등록한 CVE 레코드는 CVSS 4.0 기준 9.2(Critical)입니다. NVD는 10월 29일 현재 자체 평가 전(Awaiting Analysis) 상태입니다.

Node.js만의 문제가 아닙니다

원인이 Google Brotli 라이브러리(1.0.3~1.2.0)라서 이를 포함한 다른 소프트웨어도 영향을 받습니다. Tenable은 .NET, Bun, Envoy Proxy, Istio, Python HTTP 클라이언트, FFmpeg, Apache Arrow, ClickHouse 등을 예로 들었습니다. 그래서 Python2Shell, Brotli2Shell 등 여러 별칭으로도 불립니다. 대부분 수정 버전이 나왔고, 리눅스 배포판 패키지도 순차적으로 반영 중이므로 각 제품·배포판 공지를 함께 확인해야 합니다.

내 서버 버전 확인하기

결과가 v22.23.4 / v24.22.1 / v26.12.1 미만이면 업데이트 대상입니다.

node -v

번들된 OpenSSL·c-ares·Undici 버전까지 한 번에 보려면 아래 명령을 씁니다.

node -p "[process.version, 'openssl ' + process.versions.openssl, 'c-ares ' + process.versions.ares, 'undici ' + process.versions.undici].join('\n')"

서버 한 대에 여러 Node.js가 깔려 있는 경우가 많으니 아래도 같이 확인합니다.

# 설치된 node 실행 파일 위치 전부 확인
which -a node

# nvm 사용 시 설치된 버전 목록
nvm ls

# 실행 중인 컨테이너의 Node.js 버전
docker exec <컨테이너명> node -v

업데이트 방법

설치 방식에 맞는 방법 하나만 골라 진행하면 됩니다. 예시는 Node.js 24 기준이며, 22나 26을 쓰면 숫자만 바꿉니다.

1. nvm으로 설치한 경우

nvm install 24
nvm alias default 24
node -v   # v24.22.1 이상 확인

전역 npm 패키지(pm2 등)는 버전별로 따로 설치되므로, 새 버전에서 다시 설치해야 할 수 있습니다.

2. NodeSource 저장소(apt / dnf)로 설치한 경우

# Ubuntu / Debian
sudo apt update
sudo apt install --only-upgrade nodejs

# Rocky / Alma / RHEL
sudo dnf upgrade nodejs

node -v

배포판·저장소에 따라 수정 버전 반영이 늦을 수 있습니다. 업데이트 후 버전이 그대로라면 공식 바이너리나 nvm 설치를 고려합니다.

3. Docker 컨테이너인 경우

호스트를 업데이트해도 컨테이너 안의 Node.js는 바뀌지 않습니다. 베이스 이미지를 새로 받아 다시 빌드해야 합니다. 공식 node 이미지는 10월 21일 수정 버전으로 갱신됐습니다.

docker pull node:24
docker build --pull -t <이미지명> .
docker run --rm node:24 node -v   # v24.22.1 이상 확인

Dockerfile에 FROM node:24.22.0처럼 버전을 고정했다면 태그를 직접 올려야 합니다.

4. 서비스 재시작

바이너리를 바꿔도 실행 중인 프로세스는 이전 버전으로 계속 돕니다. 반드시 재시작합니다.

# pm2
pm2 restart all
pm2 update   # pm2 데몬도 새 Node.js로 재기동

# systemd
sudo systemctl restart <서비스명>

바로 업데이트하기 어렵다면 (임시 조치)

아래는 업데이트 전까지 위험을 줄이는 방법일 뿐, 패치를 대신하지 못합니다.

  • 압축된 요청 본문이 필요 없는 서비스라면 body-parser에 inflate: false를 설정해, 압축 해제 전에 인코딩된 요청을 거부합니다.
  • 앞단 프록시·WAF에서 외부의 Content-Encoding: br 요청 본문을 차단하거나 제한합니다. 단, 서비스가 직접 fetch()로 받아오는 응답은 WAF로 막을 수 없습니다.
  • 같은 경로에 별도 DoS 취약점(CVE-2026-111181)도 있으므로 body-parser를 2.4.0 또는 1.20.9 이상으로 함께 올립니다.

공개된 침해 지표(IoC)는 거의 없습니다. 압축 해제 중 프로세스가 갑자기 종료되거나 Brotli 디코더 오류가 반복되면, 해당 서버의 Node.js 버전과 요청 출처를 함께 확인해 보는 것이 좋습니다.

업데이트 후 확인과 주의 사항

대부분 코드 수정 없이 업데이트만으로 끝나지만, 아래 항목은 따로 챙겨야 합니다.

  • 실행 중인 프로세스가 새 버전으로 떴는지 확인 (ps -ef | grep node, 앱 로그의 process.version)
  • Docker 이미지, CI 러너, 빌드 서버까지 모두 재빌드했는지 확인
  • 단일 실행 파일(SEA)이나 스타트업 스냅샷을 쓰면 새 버전으로 다시 빌드
  • 프로젝트가 npm undici 패키지를 직접 쓰면 해당 패키지도 별도로 업데이트
  • Node.js 20 이하 서버는 22 또는 24로 이전 일정 수립

동작이 바뀌는 부분도 두 가지 있습니다. 0127.0.0.1처럼 비정규 IP 표기로 TLS 접속하면 이제 인증서 검증에서 실패하고, dns.resolve에 NUL 문자가 들어간 이름을 넘기면 오류가 발생합니다. 정상적인 사용이라면 영향이 없습니다.

외부에 노출되지 않은 내부 서비스도 외부 API를 호출하는 과정에서 영향을 받을 수 있습니다. 다만 긴급도는 상대적으로 낮으므로, 외부 요청을 직접 받는 서버부터 순서대로 진행하면 됩니다.

마무리

이번 업데이트는 설정 변경으로 막을 방법이 없고, 버전을 올리는 것만이 해결책입니다. 특히 Brotli 압축 데이터를 받거나 외부 URL을 호출하는 서비스라면 가능한 빨리 22.23.4 / 24.22.1 / 26.12.1 이상으로 올리고 재시작까지 마무리하시길 권합니다.

참고 자료

 

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다