데일리 · 기사 02 · 9 분 읽기
- 보안
- 오픈소스
Node.js, 원격 코드 실행 취약점 등을 고친 보안 수정판 공개
10월 21일 공식 발표 · 22일 입력 경로·피해 조건 해설 보완
요약·개요
Node.js가 10월 21일 보안 수정판 22.23.4·24.22.1·26.12.1을 공개했습니다. 조작된 Brotli 압축 자료를 푸는 처리에서 코드 실행으로 이어질 수 있으며, 피해 범위는 그 프로그램의 권한에 달려 있습니다.
내 서비스가 외부에서 받은 압축 자료를 푸는 순간, 그 자료가 서버를 공격하는 입구가 될 수 있습니다. 10월 21일 Node.js가 공개한 보안 수정판은 이런 처리에서 공격자가 코드를 실행할 수 있는 결함을 고쳤습니다. 어떤 입력이 들어오고, 성공하면 무엇을 잃을 수 있는지 가상의 날씨 정보 서비스로 보겠습니다.
핵심 팩트
Node.js는 브라우저 밖에서 JavaScript 프로그램을 실행하는 환경입니다. Node.js 프로젝트는 10월 21일 보안 공지를 내고, 지원 중인 세 계열의 수정판 22.23.4·24.22.1·26.12.1을 공개했습니다. 원격 코드 실행까지 이어질 수 있는 결함은 CVE-2026-111497입니다. CVE는 공개된 취약점마다 붙는 고유 번호이고, 이 결함은 Brotli 형식으로 압축된 데이터를 푸는 코드에 있습니다. 이번 묶음의 최고 심각도는 High입니다. 공식 보안 공지
| 계열 | 수정판 | 공식 릴리스 기록 |
|---|---|---|
| 22.x | 22.23.4 | 22.23.4 릴리스 |
| 24.x | 24.22.1 | 24.22.1 릴리스 |
| 26.x | 26.12.1 | 26.12.1 릴리스 |
Node.js 릴리스 일정에서 20.x는 4월 30일로 지원이 끝난 계열이고, 이런 계열에는 수정판이 없습니다. 공지는 지원 종료 버전이 보안 릴리스 때마다 항상 영향을 받는다고 적었습니다. 공식 보안 공지
같은 릴리스에는 DNS(서버 이름으로 IP 주소를 찾는 기능)와 TLS(HTTPS 연결을 암호화하고 상대 서버의 인증서를 검증하는 규약) 관련 결함 수정, c-ares·OpenSSL·Undici 같은 내장 부품 업데이트도 들어 있습니다. 계열마다 해당하는 결함은 조금씩 다릅니다. 예를 들어 IP 주소를 전각 숫자로 적었을 때 인증서 검증을 빠져나가는 CVE-2026-105483은 24.x와 26.x에만 해당합니다.

1. Node.js는 어디에서 돌고 있나
웹 서비스에서 Node.js가 쓰이는 자리는 크게 둘입니다. 서버에서 API 요청에 답하거나, 배포 전에 웹사이트 파일을 만드는 빌드 도구로 돕니다. 가상의 안내 사이트를 예로 들면, 개발자가 Node.js로 페이지를 HTML 파일로 미리 만들고 배포 서버는 완성된 파일만 보냅니다. 방문자가 페이지를 열 때는 Node.js가 돌지 않지만, 파일을 만드는 빌드 환경에는 Node.js가 있습니다.
| 어디에 있나 | 이번 수정판과의 관계 |
|---|---|
| 방문자의 브라우저 | 관계없음. 브라우저는 자체 엔진으로 JavaScript를 실행 |
| 요청에 답하는 Node.js 서버 | 서버·컨테이너·관리형 호스팅의 Node.js를 교체 |
| 사이트 파일을 만드는 빌드 환경 | 빌드 도구가 쓰는 Node.js를 교체 |
고양이와 풀어보기 Q&A
- 고양이 연구원
우리 사이트는 정적 파일만 내보내는데, 이번 업데이트는 신경 안 써도 돼?
포켓 노트빌드 환경은 바꿔야 해. 방문자 요청에는 Node.js가 안 돌아도, 그 파일을 만드는 빌드 서버에는 Node.js가 있으니까.
2. 업로드 창이 없어도 들어오는 압축 자료
날씨를 보여 주는 가상의 서비스를 생각해 봅시다. 내 Node.js 서버가 외부 날씨 제공 서버에 자료를 요청하고, 돌아온 압축 자료를 풀어 기온을 화면에 표시합니다. Brotli는 웹에서 데이터를 작게 보내려고 쓰는 압축 형식이고, 받은 자료를 다시 읽을 수 있게 푸는 기능도 Node.js에 들어 있습니다. Node.js 공식 문서에도 외부 HTTP 응답을 받아 Brotli로 푸는 예제가 나옵니다. 공식 압축 응답 처리 예제
평소에는 기온 자료가 들어옵니다. 그런데 공격자가 그 응답의 내용을 조작할 수 있고, 조작한 자료가 수정 전 Node.js의 취약한 압축 해제 처리까지 도달한다면 공격의 입구가 생깁니다. 여기서 공격자가 보내는 것은 처음부터 정상적으로 실행해 달라고 맡긴 프로그램이 아니라, 앱이 읽으려던 자료입니다.
어떤 서비스가 이 경로를 갖는지는 구현에 따라 다릅니다. 올린 파일을 Brotli로 푸는 기능, 외부의 압축된 응답을 읽는 기능, 빌드 중 외부 자료를 받아 푸는 작업을 찾아보는 이유입니다. 모든 파일 업로드나 모든 HTTP 요청이 곧바로 이 결함을 실행하는 것은 아닙니다.
고양이와 풀어보기 Q&A
- 고양이 연구원
방문자가 입력하는 칸이 없는데, 공격자 자료가 어디로 들어와?
포켓 노트이 예에서는 내 서버가 다른 서버에서 받아 오는 응답이 입구야. 공격자가 그 내용에 영향을 줄 수 있고 앱이 취약한 Brotli 처리로 풀어야 하므로, 화면의 입력창 유무만으로는 판단할 수 없어.
- 고양이 연구원
날씨 제공 업체의 자료를 공격자가 어떻게 바꿔?
포켓 노트자료 제공 서버가 침해됐거나, 서비스가 공격자가 운영하는 서버의 응답을 읽는 상황을 가정한 거야. 모든 외부 API가 조작된다는 뜻이 아니라, 공격자가 영향을 줄 수 있는 자료가 내 앱에 들어올 경로를 찾는 거지.
3. 자료를 읽다가 왜 명령 실행까지 이어질까
메모리는 프로그램이 일하는 동안 자료를 잠깐 놓아 두는 공간입니다. 압축을 푸는 코드는 정해진 칸 안에 결과를 써야 하는데, 이번 결함은 그 칸 밖에까지 쓰는 문제입니다. 이를 범위 밖 쓰기라고 합니다. Node.js 공지는 CVE-2026-111497이 원격 코드 실행(RCE)으로 이어질 수 있다고 명시했습니다. 공식 보안 공지
작업대에 ‘받은 자료를 정리하는 칸’과 ‘작업에 필요한 다른 메모’가 있다고 생각해 보세요. 자료를 자기 칸에만 적으면 문제가 없지만, 옆 칸까지 덮어쓰면 그 메모를 믿고 일하던 프로그램도 잘못 움직일 수 있습니다. 실제 메모리에는 데이터뿐 아니라 실행을 이어 가는 데 쓰이는 정보도 있고, 그런 정보의 손상이 특정 조건에서 공격자가 원하는 코드 실행으로 이어질 수 있습니다. MITRE의 범위 밖 쓰기 설명
그래서 위험은 ‘날씨 숫자가 틀리게 보인다’에서 끝나지 않을 수 있습니다. 원래 맡긴 일은 자료 읽기인데, 결함을 악용하면 그 프로그램이 공격자가 원하는 다른 일까지 하게 될 수 있다는 뜻입니다. 단순히 큰 자료를 받거나 메모리가 부족해지는 모든 상황이 RCE가 되는 것은 아니며, 이 글은 실제 공격 입력이나 성공 조건을 재현하지 않았습니다.
고양이와 풀어보기 Q&A
- 고양이 연구원
자료 안에 ‘비밀번호를 보내라’고 적으면 그대로 실행한다는 거야?
포켓 노트문장을 읽고 명령으로 따르는 문제가 아니야. 압축 해제 코드의 버그로 프로그램 내부 정보가 잘못 덮이고, 그 영향으로 실행이 바뀔 수 있다는 뜻이야.
- 고양이 연구원
자료가 자기 칸 밖으로 나가면 항상 해킹에 성공해?
포켓 노트항상은 아니야. 프로세스가 멈출 수도 있고, 실제 코드 실행 가능성은 메모리 상태와 실행 환경 같은 조건에 달려 있어.
4. 성공한 공격이 내 서비스에 남길 수 있는 피해
RCE가 성립하면 공격 코드는 보통 뚫린 프로그램의 권한으로 움직입니다. Node.js가 읽을 수 있는 파일·비밀 정보, 쓸 수 있는 파일, 접속할 수 있는 데이터베이스가 피해 범위를 좌우합니다. 서버의 최고 관리자 권한이나 같은 회사의 다른 서버 권한까지 자동으로 얻는다는 뜻은 아닙니다.
아래는 가능한 피해를 이해하기 위한 시나리오입니다. 이번 취약점으로 특정 서비스에서 이런 피해가 발생했다는 보도나 실험 결과가 아닙니다.
| 운영자가 겪는 일 | 어떤 조건에서 가능한가 |
|---|---|
| 서비스가 멈춤 | 메모리 손상으로 Node.js 프로세스가 종료되면 요청 처리가 실패하거나 재시작이 필요할 수 있음 |
| 자료·접속 비밀 탈취 | 프로그램이 읽을 수 있는 설정 파일·API 키를 읽고 밖으로 보낼 수 있을 때. 고객 DB 조회에는 그 DB의 접속·조회 권한도 필요 |
| 사이트 변조 | 글·페이지 파일·데이터베이스를 수정할 권한이 있으면 내용을 바꾸거나 악성 내용을 심는 피해로 이어질 수 있음 |
| 파일 암호화·랜섬웨어 | 악성 코드를 실행하고 대상 파일을 다시 쓸 권한까지 있으면 파일을 암호화해 사용하지 못하게 만드는 시나리오도 가능 |
고양이와 풀어보기 Q&A
- 고양이 연구원
랜섬웨어처럼 파일을 잠그고 돈을 요구하는 일도 가능해?
포켓 노트악성 코드가 실행되고 대상 파일에 쓸 권한도 있으면 가능한 피해 중 하나야. RCE라는 이름만으로 모든 파일이 잠기거나 이미 랜섬웨어 피해가 났다는 뜻은 아니야.
- 고양이 연구원
DB 접속 키를 읽히면, 비밀키 파일 하나만 잃는 거야?
포켓 노트그 키로 접속할 수 있는 다른 서비스까지 영향이 이어질 수 있어. 실제 침해가 의심되면 패치와 함께 비밀키 교체·접근 기록 조사·자료 변경 여부 점검을 진행해야 해.
5. 같은 24.x라도 끝자리까지
가상의 서버 A가 v24.22.0을 쓴다고 해 봅시다. 계열은 24.x로 같아도 이번 수정판은 24.22.1이라서, 서버 A는 아직 수정 전입니다.
리눅스 배포판이나 관리형 호스팅은 수정 내용을 자기 패키지에 옮겨 담기도 합니다. 이를 백포트라고 합니다. 이 경우 버전 번호만으로는 판단이 어려우니, 공급자의 패키지 개정 번호와 보안 수정 이력을 함께 봅니다.
고양이와 풀어보기 Q&A
- 고양이 연구원
그럼 모든 서비스를 가장 새로운 26으로 올려야 해?
포켓 노트지금 쓰는 계열의 수정판으로 올리면 돼. 22·24·26 모두 수정판이 나왔고, 큰 버전을 옮기려면 호환성 시험부터 해야 하니까 그건 따로 계획하는 게 좋아.
6. 새 버전이 실제로 돌고 있는지
npm은 앱이 가져다 쓰는 패키지를 관리하는 도구입니다. 이번 수정은 Node.js 본체와 그 안에 든 부품에 있어서, npm update로 앱의 패키지를 올려도 해결되지 않습니다. Node.js 실행 파일이나 그것을 담은 컨테이너 이미지를 바꿔야 합니다.
| 바꾼 것 | 그것만으로는 알 수 없는 것 |
|---|---|
| 앱의 npm 패키지 | 서버의 Node.js 실행 파일이 바뀌었는지 |
| 개발자 노트북의 Node.js | 운영 서버·컨테이너의 Node.js가 바뀌었는지 |
| 컨테이너 설정 파일 | 새 이미지가 빌드되어 실제로 배포됐는지 |
| 관리 화면에서 고른 계열 | 실행 중인 서비스에 수정 패키지가 반영됐는지 |
- Node.js가 도는 서버·컨테이너·빌드 환경을 목록으로 적습니다.
- 각 환경의 수정 패키지를 구하고 앱 호환성을 시험합니다.
- 실행 파일이나 이미지를 교체하고 필요한 재시작·재배포를 합니다.
- 실행 중인 버전과 실제 주요 기능을 다시 대조합니다.
마지막 점검에서는 로그인, API 응답, 외부 HTTPS 통신, 압축된 응답 처리처럼 이번 수정과 맞닿은 기능을 한 번씩 돌려 봅니다.
고양이와 풀어보기 Q&A
- 고양이 연구원
서버에서 실제로 도는 버전은 어떻게 알아?
포켓 노트서비스가 도는 그 자리에서 물어봐야 해. 컨테이너라면 그 안에서
node --version을 실행하고, 관리형 호스팅이라면 공급자 화면이나 배포 기록에서 Node.js 버전을 봐. 노트북 터미널에 나오는 번호는 그 터미널이 고른 Node.js일 뿐이야. - 고양이 연구원
공지에 RCE라고 적혀 있으면 우리 서버가 이미 뚫렸다는 뜻이야?
포켓 노트그렇지는 않아. 공지는 결함과 수정판을 알리는 것이고, 실제로 침입이 있었는지는 로그와 접근 기록을 따로 조사해야 알 수 있어. 수정판을 깔아도 지난 일까지 알려 주지는 않아.
마무리
업데이트 전에 기억할 것
이번 수정판은 Node.js가 실제로 도는 곳에 들어가야 효과가 있습니다. 서버, 컨테이너, 빌드 환경을 하나씩 짚고 각각을 지금 쓰는 계열의 수정판으로 올리면 됩니다. 20.x처럼 지원이 끝난 계열을 쓰고 있다면 이번에는 고칠 버전이 없으니, 지원 계열로 옮길 계획부터 세워야 합니다.
앱과 실행 환경을 나눠 업데이트하는 방법은 PHP 보안 수정 기사에서도 다뤘습니다.
출처
- 공식 보안 공지nodejs.org
- 22.23.4 릴리스nodejs.org
- 24.22.1 릴리스nodejs.org
- 26.12.1 릴리스nodejs.org
- 릴리스 일정github.com
- 공식 압축 응답 처리 예제nodejs.org
- MITRE의 범위 밖 쓰기 설명cwe.mitre.org