압축 해제가 해킹의 통로가 된다?
웹 애플리케이션이 데이터를 압축 해제하는 과정에서 서버의 메모리가 손상될 수 있다. 2026년 10월 공개된 CVE-2026-111497은 Node.js에 포함된 Brotli 디코더가 비정상적인 압축 데이터를 잘못 처리하면서 발생하는 범위 밖 쓰기(out-of-bounds write) 취약점이다. Imperva Red Team은 이를 ‘Node2Shell’로 명명했다. 공격자가 조작한 압축 데이터로 서비스 장애나 메모리 정보 노출을 유발할 수 있으며, 특정 조건에서는 원격 코드 실행까지 가능하다. Node2Shell의 발생 원리와 실제 공격 경로, 대응 방안을 살펴보자.

압축 데이터의 오류를 잘못 판단한 Brotli 디코더
웹에서 데이터를 주고받을 때는 전송량을 줄이기 위해 원본 데이터를 압축하는 경우가 많다. 구글이 개발한 Brotli는 이러한 용도로 사용되는 압축 알고리즘 중 하나로, 데이터를 수신하는 쪽에서는 Brotli 디코더를 통해 압축된 내용을 복원한다.
Brotli 디코더는 압축 데이터를 블록 단위로 나눠 순차적으로 처리한다. 압축 데이터에는 현재 블록에서 처리할 분량과 복원해야 할 내용에 관한 지시가 포함돼 있다. 따라서 현재 블록의 분량을 다 처리했더라도 풀 내용이 남았다면 다음 블록으로 넘어가 작업을 이어간다.
문제는 공격자가 이러한 처리 과정에 맞지 않게 압축 데이터를 디코더에 전달했을 때 발생한다. 예를 들어 압축 데이터에는 아직 복원해야 할 내용이 남아 있지만, 현재 블록에서 처리할 수 있는 분량은 이미 소진된 상태일 수 있다. 이때 디코더는 남은 내용을 복원하기 위해 다음 블록으로 전환하려 하지만, 실제로는 이어서 처리할 블록 정보가 존재하지 않는다.
이처럼 압축 데이터의 구조가 올바르지 않다면 디코더는 오류를 반환하고 압축 해제를 중단해야 한다. 데이터를 추가로 전달받더라도 해결할 수 없는 문제이기 때문이다.
하지만 취약한 Brotli 디코더는 특정 조건에서 이 오류를 입력 데이터가 부족한 상황으로 잘못 판단한다. 이후 새로 들어온 데이터를 크기가 작은 내부 저장 공간에 담아 압축 해제를 다시 시도하지만, 애초에 데이터가 부족해서 생긴 문제가 아니기에 블록 전환이 불가능한 상태는 여전히 유지된다. 따라서 이 과정이 반복되면 내부 저장 공간의 범위를 넘어 데이터가 기록될 수 있는데, 이것이 바로 ‘범위 밖 쓰기’ 취약점이다.

[그림 1] 오류를 입력 부족으로 오인했을 때 범위 밖 쓰기로 이어지는 과정
이 밖에도 블록 전환에 실패한 사실을 확인하지 않고 압축 해제를 계속하는 문제가 확인됐다. 다만 앞서 설명한 내부 저장 공간 초과는 블록 전환 오류를 입력 데이터 부족으로 오인하는 경우에 발생한다. 수정된 디코더는 블록 전환이 불가능한 상태와 데이터가 부족한 상태를 구분하고, 잘못 구성된 압축 데이터에 대해서는 압축 해제를 중단하도록 변경됐다.
범위 밖 쓰기는 프로그램이 정해진 저장 공간을 벗어나 다른 메모리 영역에 데이터를 기록하는 문제다. 이로 인해 Node.js 프로세스의 메모리가 손상되면 서비스가 중단되거나 메모리 정보가 노출될 수 있다. 또한 실행 환경과 메모리 구조 등 여러 조건이 충족되면 공격자가 서버에서 임의의 코드를 실행하는 원격 코드 실행으로도 이어질 수 있다.
Node.js 프로젝트는 이러한 위험성을 고려해 CVE-2026-111497의 심각도를 High로 평가했다. 별도로 구글이 등록한 Brotli 라이브러리의 CVE 레코드에는 CVSS v4.0 기준 9.2점이 기재돼 있다.
Node2Shell 공격은 어떤 경로로 발생할까?
공격자는 먼저 취약한 버전의 Node.js를 사용 중인 서비스를 찾는다. 다만, 버전만 취약하다고 해서 공격이 가능한 것은 아니다. 공격이 성립하려면 해당 서비스가 외부에서 전달받은 Brotli 압축 데이터를 실제로 압축 해제해야 하며, 공격자가 조작한 데이터를 해당 처리 과정까지 전달할 수 있어야 한다.
이러한 조건을 충족할 수 있는 주요 경로는 크게 세 가지다.
1. 클라이언트가 보내는 HTTP POST 요청 본문을 통한 유입
클라이언트가 서버로 보내는 HTTP 요청 본문이 Brotli 방식으로 압축돼 있을 경우 이를 지원하는 애플리케이션은 본문의 내용을 사용하기 전에 압축을 해제한다. 따라서 공격자가 조작한 압축 데이터를 요청 본문에 포함해서 전송한다면, 해당 데이터가 Brotli 디코더에 전달될 수 있는 것이다.
2. 외부 서버의 응답을 통한 유입
Node.js 애플리케이션이 외부 서버에서 받은 Brotli 압축 데이터를 해제하는 과정에서도 취약점이 발생할 수 있다. 공격자가 외부 서버의 응답을 제어하거나, 애플리케이션이 공격자가 지정한 주소에서 데이터를 가져오도록 유도하면 해당 응답에 조작된 압축 데이터를 포함할 수 있다.
3. Node.js 애플리케이션이 Brotli 데이터나 파일을 직접 처리하는 경우
조작된 데이터는 반드시 웹 요청으로 직접 전달될 필요는 없다. 애플리케이션이 Brotli로 압축된 파일이나 다른 시스템에서 전달된 메시지를 직접 압축 해제하는 경우에도 취약한 디코더가 호출될 수 있다. 파일은 웹 요청을 통해 업로드될 수 있으며, 메시지는 별도의 시스템이나 메시지 큐를 통해 전달될 수 있다.
이처럼 유입 경로와 관계없이 공격자가 조작한 압축 데이터가 취약한 디코더에서 처리되면, 특정 조건에서 블록 전환 오류를 입력 데이터 부족으로 잘못 판단할 수 있다. 이로 인해 범위 밖 쓰기가 발생하면 Node.js 프로세스의 메모리가 손상될 수 있다.

[그림 2] 공격자가 조작한 Brotli 데이터 전달부터 디코더 메모리 손상까지의 흐름
실제 공격 결과는 실행 환경에 따라 달라지며, 조작된 압축 데이터로 메모리 손상이 발생하더라도 모든 환경에서 원격 코드 실행으로 이어지는 것은 아니다. 공개된 재현에서는 특정 Node.js 빌드와 애플리케이션 구성에서 코드 실행이 확인됐으며, 취약점이 수정된 버전에서는 동일한 입력이 거부됐다.
아래 두 영상은 취약한 Node.js 환경에서 Node2Shell을 이용해 서비스 거부(DoS)와 원격 코드 실행(RCE)을 재현한 결과를 보여준다.
Node2Shell 취약점 대응 방안
1. 취약점이 수정된 버전으로 Node.js 업데이트
가장 확실한 대응 방법은 실제 서비스에서 사용 중인 Node.js를 취약점이 수정된 버전 이상으로 업데이트하는 것이다. Node.js 프로젝트가 2026년 10월 21일 발표한 계열별 첫 수정 버전은 다음과 같다.
|
Node.js 계열 |
취약 버전 |
수정 버전 |
|---|---|---|
|
22.x |
22.23.4 미만 |
22.23.4 이상 |
|
24.x |
24.22.1 미만 |
24.22.1 이상 |
|
26.x |
26.12.1 미만 |
26.12.1 이상 |
[표 1] Node.js 프로젝트가 발표한 계열별 수정 버전
업데이트할 때는 서버에 설치된 Node.js 버전뿐만 아니라 실제 서비스가 사용하는 실행 파일과 버전도 확인해야 한다. Node.js 실행 파일이 컨테이너 이미지나 배포 파일에 별도로 포함돼 있을 수 있기 때문이다. 따라서 이러한 실행 파일까지 수정 버전으로 교체하고 관련 프로세스를 다시 시작해야 한다. 이후 실행 중인 서비스에 수정 버전이 적용됐는지 확인하고, Node.js 외의 다른 제품이 Brotli 라이브러리를 별도로 사용하고 있다면 해당 제품의 패치 적용 여부도 따로 점검할 필요가 있다.
2. 즉시 업데이트하기 어려운 경우 임시 대응
여러 서버를 차례로 업데이트해야 하거나 서비스 안정성 검증이 필요한 경우에는 패치를 즉시 적용하기 어려울 수 있다. Node.js가 제품에 포함돼 있어 제조사의 업데이트를 기다려야 하는 환경도 마찬가지다.
이 경우에는 먼저 외부에서 전달된 Brotli 데이터가 서비스 내부의 어떤 경로를 통해 압축 해제되는지 확인하고, 업데이트가 완료될 때까지 해당 경로를 일시적으로 제한해야 한다.
예를 들어 Brotli로 압축된 HTTP 요청 본문을 처리하는 기능이 있다면 해당 요청을 제한하거나, 프록시 또는 웹 방화벽(WAF)을 이용해 Brotli 압축 요청을 차단하는 방법을 고려할 수 있다.
외부 서버에서 Brotli로 압축된 응답을 받아 처리하는 기능은 허용된 서버에서만 응답을 수신하도록 제한하거나, 필요한 경우 해당 기능을 일시적으로 중단할 수 있다.
다만 이러한 조치는 공격 가능성을 낮추기 위한 임시 대응 방안이다. 정상적인 웹 요청이나 외부 시스템 연동에도 영향을 줄 수 있으므로 서비스에 필요한 기능인지 확인한 후 적용하고, 업데이트가 완료될 때까지만 유지하는 것이 적절하다.
Node2Shell은 애플리케이션에 직접 구현된 기능뿐만 아니라 런타임 내부의 데이터 처리 과정에서도 심각한 취약점이 발생할 수 있음을 보여준다. 특히 개발자가 Brotli 압축 해제 기능을 직접 호출하지 않더라도, 웹 요청이나 외부 서버의 응답을 처리하는 과정에서 취약한 디코더가 사용될 수 있다는 점이 중요하다.
따라서 유사한 취약점에 대응할 때는 사용 중인 구성 요소의 버전뿐 아니라 해당 구성 요소가 서비스의 어떤 기능에서 호출되는지, 외부에서 전달된 데이터가 그곳까지 도달할 수 있는지까지 점검해야 한다.
- AhnLab콘텐츠마케팅팀