Node.js 취약점 Node2Shell 총정리 — 보안 업데이트 버전·점검법


PHP 긴급 패치 소식에 서버를 점검하던 바로 그날, Node.js도 조용히 보안 릴리스를 내놨습니다. 처음엔 “High 등급 10건 수정” 정도로 지나가는 듯했지만, 일주일 만에 상황이 달라졌습니다. 핵심 결함인 Brotli 원격 코드 실행 취약점이 10월 27일 미국 CISA의 ‘실제 악용 취약점(KEV)’ 목록에 오르면서, 이번 Node.js 취약점은 “언젠가 올려야 할 패치”에서 “지금 당장 확인할 일”이 됐습니다. 해외에서는 Node2Shell이라는 별칭으로 불리는 이번 사태를 공식 공지와 각국 보안 기관 자료를 기준으로 정리했습니다.


이번 Node.js 취약점, 무엇이 문제인가

Node.js는 10월 21일 22.x, 24.x, 26.x 세 지원 라인에 보안 업데이트를 동시에 배포했습니다. 고친 취약점은 모두 10건으로 High 4건, Medium 3건, Low 3건입니다. 가장 주목받는 것은 CVE-2026-111497입니다.

🔹 Brotli 디코더 결함, 쉽게 말하면

Brotli는 데이터를 작게 압축하는 기술이고, 디코더는 압축을 원래대로 푸는 부품입니다. 이번 결함은 잘못 만들어진 압축 데이터를 받았을 때 멈추지 않고 계속 풀다가, 정해진 메모리 공간 밖까지 데이터를 덮어쓰는 문제입니다. 잘못 포장된 상자를 풀다가 작업대 밖에 놓인 다른 물건까지 망가뜨리는 상황과 비슷합니다. 그 결과 서비스 장애, 메모리 정보 노출, 최악의 경우 원격 코드 실행까지 이어질 수 있습니다.

중요한 조건이 하나 있습니다. Node.js를 설치했다는 사실만으로 위험한 것이 아니라, 공격자가 만든 Brotli 데이터를 내 애플리케이션이 실제로 압축 해제하는 경로가 있어야 합니다.

📌 특히 점검해야 할 코드 경로

  • 외부 URL 조회: fetch()로 외부 사이트를 불러올 때 Brotli 응답이 자동으로 풀립니다. 링크 미리보기, 크롤러, 외부 콘텐츠 수집 서비스가 1순위입니다.
  • Express 5 요청 본문 파서: Brotli로 압축된 요청 본문을 풀 수 있어, 코드에서 Brotli 함수를 직접 부르지 않아도 노출될 수 있습니다.
  • 업로드 파일 압축 해제: 업로드 받은 데이터를 brotliDecompress() 등으로 풀고 있다면 점검 대상입니다.
  • 상대적으로 덜 위험한 경우: 기본 http 서버로 요청만 받거나, 응답을 Brotli로 압축해 보내기만 하는 경로는 이번 디코더 결함과 직접 관련이 적습니다.

🔹 나머지 High 취약점 3건

  • TLS 호스트명 검증 우회(CVE-2026-105483, CVE-2026-106069): 특수한 IP 표기 때문에 실제 연결 대상과 다른 인증서를 맞다고 판단할 수 있는 문제입니다. 암호화가 깨진 것은 아니지만, 상대방 신원 확인에 구멍이 생깁니다.
  • DNS 이름 잘림(CVE-2026-105482): 도메인 허용 목록으로 검사한 이름과 실제로 조회하는 이름이 달라질 수 있습니다. 외부 URL 접근을 도메인으로 제한하는 서비스라면 확인이 필요합니다.

이 밖에 단일 실행 파일(SEA)이나 스냅샷으로 배포한 앱에서 UUID와 난수가 프로세스마다 반복될 수 있는 문제(Medium)도 함께 고쳐졌습니다. 이번 릴리스에는 eMudhra 인증서 문제에 대응한 CA 인증서 저장소 갱신도 포함되어 있습니다.


날짜별로 보는 사태 흐름

날짜 전개
10월 14일 Node.js 보안팀이 21일 무렵 High 등급 보안 릴리스 예정을 사전 공지
10월 21일 22.23.4, 24.22.1, 26.12.1 배포. 같은 날 PHP도 PHP2Shell 긴급 패치
10월 22일 공식 Node.js 빌드에서 코드 실행이 가능했다는 연구 결과 보도, 공개 PoC 등장
10월 23일 싱가포르 CSA가 CVSS v3.1 9.8점으로 평가하고 즉시 업데이트 권고
10월 26일 보안 업체가 실제 환경에서 공격 시도를 관측했다는 보도
10월 27일 미국 CISA가 KEV 목록에 등재
10월 28일 홍콩 HKCERT가 실제 악용을 명시하며 ‘매우 높은 위험’으로 분류

PHP2Shell과 같은 날 공개돼 함께 보도됐지만, 두 사건은 CVE도 결함도 전혀 다른 별개의 문제입니다. 하루에 웹 서버 런타임 두 개가 동시에 긴급 패치를 내다 보니 해외 언론은 “인터넷이 아주 나쁜 날을 보내고 있다”고 표현하기도 했습니다.

🤖 이번에도 AI가 찾았다

Node.js 공식 공지에는 Brotli 취약점 제보자로 OpenAI Codex Security 연구진이 적혀 있습니다. OpenAI는 이 결함의 근본 원인이 2026년 2월 Brotli 소스에서 이미 고쳐졌지만, 당시에는 보안 문제로 인식되지 않아 릴리스에 반영되지 않았다고 설명했습니다. 다만 AI가 사람 개입 없이 혼자 찾아냈는지, 10건 전부를 AI가 찾았는지는 확인되지 않았습니다. 공식 공지에는 취약점마다 서로 다른 제보자가 적혀 있습니다.


Node.js 보안 업데이트 버전과 EOL 버전

Node.js 보안 업데이트의 기준 버전은 다음과 같습니다. 이보다 낮다면 업데이트 대상입니다.

지원 라인 수정 버전 상태
22.x 22.23.4 LTS
24.x 24.22.1 LTS
26.x 26.12.1 Current
20.x·21.x·23.x·25.x 공식 패치 없음 지원 종료(EOL)

🔴 Node.js 20 사용자라면

Node.js 20은 2026년 4월 30일 지원이 끝나 이번 패치를 받지 못합니다. 여기서 흔한 오해가 “패치가 없으니 영향도 없겠지”입니다. 패치가 없다는 것과 취약하지 않다는 것은 전혀 다른 이야기입니다. 가장 확실한 방법은 22나 24 LTS로 옮기는 것이고, 상용 연장 지원 서비스를 쓴다면 이 CVE를 고친 빌드가 실제로 제공됐는지 계약 범위와 함께 확인해야 합니다.

🔹 설치 방식별 업데이트 포인트

  • nodejs.org 설치 파일: 같은 메이저 라인의 수정 버전으로 교체하고 서비스를 재시작합니다.
  • nvm·Volta: 도구 자체가 아니라 도구가 고르는 Node.js 버전을 바꿔야 합니다. 내 계정의 Node.js와 systemd·PM2·CI가 쓰는 Node.js가 다를 수 있습니다.
  • Docker: 실행 중인 컨테이너는 자동으로 바뀌지 않습니다. 패치된 베이스 이미지로 앱 이미지를 다시 빌드해서 배포해야 합니다.
  • 리눅스 배포판 패키지: 배포판이 보안 수정을 백포트하면 버전 숫자는 그대로일 수 있습니다. 반대로 OS의 Brotli 라이브러리만 올려도, Node.js 안에 Brotli가 내장돼 있으면 해결되지 않을 수 있습니다.
  • SEA·스냅샷·Electron: 런타임이 결과물 안에 들어 있으므로, 패치된 Node.js로 다시 만들어 배포해야 합니다.
  • 클라우드: AWS Elastic Beanstalk는 10월 22일 수정 버전을 반영했다고 공지했습니다. 하지만 Lambda, Vercel, Netlify 등 다른 서비스의 반영 시점은 서비스별로 따로 확인해야 합니다.

국내외 기관 대응

해외에서는 싱가포르 CSA(10월 23일), 미국 CIS·MS-ISAC(10월 27일), 홍콩 HKCERT(10월 28일)가 차례로 권고를 냈고, CISA는 KEV에 등재했습니다. 미국 연방 기관의 조치 기한은 11월 10일로 보도됐는데, 이는 미국 연방 기관 대상 기한이지 국내 기업의 법정 기한은 아닙니다.

국내에서는 KISA가 업데이트를 권고했다는 언론 보도가 나왔고, 이스트시큐리티 등 보안 업체도 긴급 업데이트 권고를 냈습니다. 네이버클라우드 공공 플랫폼도 Node.js 원격 코드 실행 취약점 보안 업데이트 권고를 게시했습니다. 다만 클라우드가 업데이트를 권고한 것과, 내가 쓰는 런타임까지 패치를 끝낸 것은 다른 이야기라는 점을 기억해 두세요.


노드js 버전 확인과 업데이트 순서

노드js 버전 확인에서 가장 중요한 것은 내 PC의 Node.js가 아니라 실제 서비스가 돌고 있는 Node.js를 보는 것입니다.

1. 🔍 실행 중인 버전 확인

# 현재 셸에서 잡히는 Node.js 버전과 위치
node --version
node -p "process.execPath"
type -a node

# 실행 중인 Node.js 프로세스와 시작 시각
ps -eo pid,lstart,args | grep -E '[n]ode( |$)'

# 컨테이너 이미지의 런타임 확인
docker run --rm YOUR_IMAGE node --version

업데이트를 했더라도 프로세스 시작 시각이 업데이트 이전이라면, 옛 버전이 여전히 메모리에서 돌고 있다는 뜻입니다.

2. 📋 업데이트 순서

  1. 자산 목록 만들기: 운영 API, 외부 URL 조회 워커, CI 러너, 컨테이너, SEA·Electron 배포물을 나눠서 적습니다.
  2. 우선순위 정하기: 외부에서 받은 데이터나 외부 서버 응답을 Brotli로 푸는 서비스를 먼저 합니다.
  3. 같은 라인 수정 버전 적용: 22는 22.23.4, 24는 24.22.1처럼 같은 메이저 라인으로 먼저 올립니다. EOL 버전은 별도 이전 계획을 세웁니다.
  4. 회귀 테스트: 네이티브 모듈 로딩, TLS 연결, 프록시, DNS, 압축 응답을 확인합니다.
  5. 결과물 재생성과 재배포: 이미지·SEA·스냅샷을 다시 만들고, 모든 복제본과 백그라운드 워커가 교체됐는지 확인합니다.

npm audit가 조용하다고 안심하면 안 됩니다. 의존성 점검과 Node.js 런타임 패치는 서로 다른 관리 대상입니다.

3. ⏳ 당장 업데이트가 어렵다면

Node.js 공식 공지에는 별도의 우회책이 없습니다. CIS·MS-ISAC는 패치 전 임시 조치로 다음을 권고했습니다.

  • Brotli 요청 본문 거부: 필요 없다면 프록시나 로드밸런서에서 Content-Encoding: br 요청 본문을 막습니다. 다만 외부 응답을 푸는 경로는 막지 못합니다.
  • 신뢰할 수 없는 압축 해제 제한: 외부 데이터를 Brotli로 푸는 기능을 꺼 둡니다.
  • 최소 권한·네트워크 분리: 침해되더라도 피해를 줄이는 보완책입니다.

인증서 오류가 난다고 TLS 검증(rejectUnauthorized)을 끄는 것은 절대 대응책이 아닙니다.

4. 🕵️ 침해 흔적 점검

이번 CVE만을 특정하는 국내 침해 지표는 아직 공개되지 않았습니다. 대신 패치 전 기간 동안 비정상 종료나 재시작 급증, Node.js 프로세스가 띄운 낯선 자식 프로세스, 예상치 못한 외부 연결, 새로 생긴 파일이나 예약 작업이 없었는지 로그를 시간순으로 맞춰 보세요. 침해가 의심되면 증거를 남긴 뒤 격리하고, 깨끗한 이미지로 다시 배포하고, 노출됐을 수 있는 자격 증명을 교체해야 합니다.


Node.js 밖으로 번지는 영향과 헷갈리기 쉬운 것들

🔹 Brotli는 Node.js만의 부품이 아니다

이번 결함은 Node.js가 직접 만든 코드가 아니라, 구글이 만든 공통 압축 라이브러리 Brotli에서 나왔습니다. 그래서 홍콩 HKCERT는 이번 권고의 제목을 아예 “Google Brotli 원격 코드 실행 취약점”으로 달고, Node.js 외에 Brotli를 쓰는 제품까지 즉시 패치하라고 권고했습니다. 해외 보안 연구자들은 Python, Go, .NET 생태계의 일부 도구에도 같은 계열의 영향이 있다고 분석했고, PHP 윈도우 빌드도 Brotli 대응판이 나왔다는 보도가 있습니다.

즉 “우리 회사는 Node.js 서버가 몇 대 없으니 괜찮다”로 끝낼 문제가 아닙니다. 개발자 PC의 빌드 도구, 사내 배포 도구, 데스크톱 앱처럼 제품 안에 Brotli가 숨어 있는 곳까지 SBOM(소프트웨어 구성 목록)으로 확인해 두는 것이 좋습니다.

🔹 런타임 취약점과 npm 공급망 공격은 다르다

최근 몇 달 사이 npm에서는 악성 패키지와 계정 탈취를 이용한 공급망 공격 소식도 이어졌습니다. 두 문제는 이름이 함께 오르내리지만 성격이 다릅니다.

  • 런타임 취약점(이번 사태): 정상적으로 배포된 Node.js 실행 파일 안에 결함이 있는 경우입니다. 대응은 Node.js 버전 업데이트와 재배포입니다.
  • npm 공급망 공격: 내가 설치하는 패키지나 배포 계정 자체가 오염된 경우입니다. 대응은 잠금 파일 관리, 패키지 출처 검증, 배포 계정 2단계 인증입니다.

두 가지를 하나의 점검으로 묶으면 어느 한쪽이 빠지기 쉽습니다. 런타임 버전 관리와 의존성 관리를 서로 다른 체크리스트로 운영하는 습관이 필요합니다.


총평: ‘어디서 Node.js가 도는지’ 아는 팀이 이긴다

이번 사태는 두 가지를 보여줬습니다. 하나는 AI가 취약점을 찾는 속도가 빨라지면서 소스에 수정이 들어간 것과 사용자 서버에 패치가 깔린 것 사이의 간격이 그대로 위험이 된다는 점입니다. 다른 하나는 Brotli처럼 공통 라이브러리의 결함은 Node.js를 넘어 개발 도구와 다른 언어 제품까지 번진다는 점입니다.

정리하면 이번 Node.js 취약점 대응은 세 단계입니다. 실제 서비스의 Node.js 버전을 확인하고, Node.js 보안 업데이트(22.23.4·24.22.1·26.12.1)를 적용해 이미지와 프로세스까지 교체한 뒤, 패치 전 기간의 로그를 점검하는 것입니다. 이미 실제 공격 단계에 들어선 만큼 미루지 않으시길 권합니다. 새로운 권고나 국내 피해 소식이 나오면 이 글에 업데이트하겠습니다.


자주 묻는 질문

Q.npm update나 npm audit fix를 하면 이번 Node.js 취약점이 해결되나요?
A.아니요. 이번 문제는 npm 패키지가 아니라 Node.js 실행 파일 자체에 들어 있는 Brotli 디코더의 결함입니다. 의존성 점검과 별개로 Node.js를 22.23.4, 24.22.1, 26.12.1 이상으로 바꾸고 서비스를 다시 띄워야 합니다.
Q.Node.js 20을 쓰고 있는데 패치가 없나요?
A.Node.js 20은 2026년 4월 30일 지원이 끝나 이번 공식 수정 버전을 받지 못합니다. 23, 25 같은 홀수 버전도 마찬가지입니다. 22나 24 LTS로 옮기는 것이 가장 확실하고, 상용 연장 지원을 쓴다면 이 CVE를 고친 빌드가 실제로 나왔는지 확인해야 합니다.
Q.Docker 이미지를 쓰면 자동으로 패치되나요?
A.이미 떠 있는 컨테이너는 바뀌지 않습니다. 패치된 node 베이스 이미지로 앱 이미지를 다시 빌드하고 재배포한 뒤, 컨테이너 안의 node --version과 이미지 digest로 반영 여부를 확인해야 합니다.
Q.Express나 Next.js만 최신으로 올리면 되나요?
A.프레임워크 업데이트와 Node.js 런타임 업데이트는 별개입니다. 다만 Express 5의 요청 본문 파서나 Next.js 자체 호스팅 이미지 최적화처럼 Brotli를 풀 수 있는 경로가 있다면 우선 점검 대상이므로, 런타임을 먼저 올리는 것이 순서입니다.
Q.CVSS 점수가 9.8과 9.2로 다른데 위험도가 낮아진 건가요?
A.아닙니다. 싱가포르 CSA는 CVSS v3.1로 9.8, GitHub 보안 권고는 CVSS v4.0으로 9.2를 매겼습니다. 계산 방식이 다를 뿐 위험이 줄어든 것이 아니며, Node.js 자체 분류는 High입니다.
#IT보안#Nodejs#Node2Shell

관련 글

PHP 취약점 PHP2Shell 총정리 — 보안 업데이트 버전·점검·대응법
2026.10.26

Written by@namu
모바일, 스마트폰, 금융, 재테크, 생활 정보 등