2026-10-28 21:50
PHP 긴급 패치 소식에 서버를 점검하던 바로 그날, Node.js도 조용히 보안 릴리스를 내놨습니다. 처음엔 “High 등급 10건 수정” 정도로 지나가는 듯했지만, 일주일 만에 상황이 달라졌습니다. 핵심 결함인 Brotli 원격 코드 실행 취약점이 10월 27일 미국 CISA의 ‘실제 악용 취약점(KEV)’ 목록에 오르면서, 이번 Node.js 취약점은 “언젠가 올려야 할 패치”에서 “지금 당장 확인할 일”이 됐습니다. 해외에서는 Node2Shell이라는 별칭으로 불리는 이번 사태를 공식 공지와 각국 보안 기관 자료를 기준으로 정리했습니다.
Node.js는 10월 21일 22.x, 24.x, 26.x 세 지원 라인에 보안 업데이트를 동시에 배포했습니다. 고친 취약점은 모두 10건으로 High 4건, Medium 3건, Low 3건입니다. 가장 주목받는 것은 CVE-2026-111497입니다.
Brotli는 데이터를 작게 압축하는 기술이고, 디코더는 압축을 원래대로 푸는 부품입니다. 이번 결함은 잘못 만들어진 압축 데이터를 받았을 때 멈추지 않고 계속 풀다가, 정해진 메모리 공간 밖까지 데이터를 덮어쓰는 문제입니다. 잘못 포장된 상자를 풀다가 작업대 밖에 놓인 다른 물건까지 망가뜨리는 상황과 비슷합니다. 그 결과 서비스 장애, 메모리 정보 노출, 최악의 경우 원격 코드 실행까지 이어질 수 있습니다.
중요한 조건이 하나 있습니다. Node.js를 설치했다는 사실만으로 위험한 것이 아니라, 공격자가 만든 Brotli 데이터를 내 애플리케이션이 실제로 압축 해제하는 경로가 있어야 합니다.
fetch()로 외부 사이트를 불러올 때 Brotli 응답이 자동으로 풀립니다. 링크 미리보기, 크롤러, 외부 콘텐츠 수집 서비스가 1순위입니다.brotliDecompress() 등으로 풀고 있다면 점검 대상입니다.http 서버로 요청만 받거나, 응답을 Brotli로 압축해 보내기만 하는 경로는 이번 디코더 결함과 직접 관련이 적습니다.이 밖에 단일 실행 파일(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도 결함도 전혀 다른 별개의 문제입니다. 하루에 웹 서버 런타임 두 개가 동시에 긴급 패치를 내다 보니 해외 언론은 “인터넷이 아주 나쁜 날을 보내고 있다”고 표현하기도 했습니다.
Node.js 공식 공지에는 Brotli 취약점 제보자로 OpenAI Codex Security 연구진이 적혀 있습니다. OpenAI는 이 결함의 근본 원인이 2026년 2월 Brotli 소스에서 이미 고쳐졌지만, 당시에는 보안 문제로 인식되지 않아 릴리스에 반영되지 않았다고 설명했습니다. 다만 AI가 사람 개입 없이 혼자 찾아냈는지, 10건 전부를 AI가 찾았는지는 확인되지 않았습니다. 공식 공지에는 취약점마다 서로 다른 제보자가 적혀 있습니다.
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은 2026년 4월 30일 지원이 끝나 이번 패치를 받지 못합니다. 여기서 흔한 오해가 “패치가 없으니 영향도 없겠지”입니다. 패치가 없다는 것과 취약하지 않다는 것은 전혀 다른 이야기입니다. 가장 확실한 방법은 22나 24 LTS로 옮기는 것이고, 상용 연장 지원 서비스를 쓴다면 이 CVE를 고친 빌드가 실제로 제공됐는지 계약 범위와 함께 확인해야 합니다.
해외에서는 싱가포르 CSA(10월 23일), 미국 CIS·MS-ISAC(10월 27일), 홍콩 HKCERT(10월 28일)가 차례로 권고를 냈고, CISA는 KEV에 등재했습니다. 미국 연방 기관의 조치 기한은 11월 10일로 보도됐는데, 이는 미국 연방 기관 대상 기한이지 국내 기업의 법정 기한은 아닙니다.
국내에서는 KISA가 업데이트를 권고했다는 언론 보도가 나왔고, 이스트시큐리티 등 보안 업체도 긴급 업데이트 권고를 냈습니다. 네이버클라우드 공공 플랫폼도 Node.js 원격 코드 실행 취약점 보안 업데이트 권고를 게시했습니다. 다만 클라우드가 업데이트를 권고한 것과, 내가 쓰는 런타임까지 패치를 끝낸 것은 다른 이야기라는 점을 기억해 두세요.
노드js 버전 확인에서 가장 중요한 것은 내 PC의 Node.js가 아니라 실제 서비스가 돌고 있는 Node.js를 보는 것입니다.
# 현재 셸에서 잡히는 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업데이트를 했더라도 프로세스 시작 시각이 업데이트 이전이라면, 옛 버전이 여전히 메모리에서 돌고 있다는 뜻입니다.
npm audit가 조용하다고 안심하면 안 됩니다. 의존성 점검과 Node.js 런타임 패치는 서로 다른 관리 대상입니다.
Node.js 공식 공지에는 별도의 우회책이 없습니다. CIS·MS-ISAC는 패치 전 임시 조치로 다음을 권고했습니다.
Content-Encoding: br 요청 본문을 막습니다. 다만 외부 응답을 푸는 경로는 막지 못합니다.인증서 오류가 난다고 TLS 검증(rejectUnauthorized)을 끄는 것은 절대 대응책이 아닙니다.
이번 CVE만을 특정하는 국내 침해 지표는 아직 공개되지 않았습니다. 대신 패치 전 기간 동안 비정상 종료나 재시작 급증, Node.js 프로세스가 띄운 낯선 자식 프로세스, 예상치 못한 외부 연결, 새로 생긴 파일이나 예약 작업이 없었는지 로그를 시간순으로 맞춰 보세요. 침해가 의심되면 증거를 남긴 뒤 격리하고, 깨끗한 이미지로 다시 배포하고, 노출됐을 수 있는 자격 증명을 교체해야 합니다.
이번 결함은 Node.js가 직접 만든 코드가 아니라, 구글이 만든 공통 압축 라이브러리 Brotli에서 나왔습니다. 그래서 홍콩 HKCERT는 이번 권고의 제목을 아예 “Google Brotli 원격 코드 실행 취약점”으로 달고, Node.js 외에 Brotli를 쓰는 제품까지 즉시 패치하라고 권고했습니다. 해외 보안 연구자들은 Python, Go, .NET 생태계의 일부 도구에도 같은 계열의 영향이 있다고 분석했고, PHP 윈도우 빌드도 Brotli 대응판이 나왔다는 보도가 있습니다.
즉 “우리 회사는 Node.js 서버가 몇 대 없으니 괜찮다”로 끝낼 문제가 아닙니다. 개발자 PC의 빌드 도구, 사내 배포 도구, 데스크톱 앱처럼 제품 안에 Brotli가 숨어 있는 곳까지 SBOM(소프트웨어 구성 목록)으로 확인해 두는 것이 좋습니다.
최근 몇 달 사이 npm에서는 악성 패키지와 계정 탈취를 이용한 공급망 공격 소식도 이어졌습니다. 두 문제는 이름이 함께 오르내리지만 성격이 다릅니다.
두 가지를 하나의 점검으로 묶으면 어느 한쪽이 빠지기 쉽습니다. 런타임 버전 관리와 의존성 관리를 서로 다른 체크리스트로 운영하는 습관이 필요합니다.
이번 사태는 두 가지를 보여줬습니다. 하나는 AI가 취약점을 찾는 속도가 빨라지면서 소스에 수정이 들어간 것과 사용자 서버에 패치가 깔린 것 사이의 간격이 그대로 위험이 된다는 점입니다. 다른 하나는 Brotli처럼 공통 라이브러리의 결함은 Node.js를 넘어 개발 도구와 다른 언어 제품까지 번진다는 점입니다.
정리하면 이번 Node.js 취약점 대응은 세 단계입니다. 실제 서비스의 Node.js 버전을 확인하고, Node.js 보안 업데이트(22.23.4·24.22.1·26.12.1)를 적용해 이미지와 프로세스까지 교체한 뒤, 패치 전 기간의 로그를 점검하는 것입니다. 이미 실제 공격 단계에 들어선 만큼 미루지 않으시길 권합니다. 새로운 권고나 국내 피해 소식이 나오면 이 글에 업데이트하겠습니다.