* 출처는 안랩입니다.
웹 애플리케이션이 데이터를 압축 해제하는 과정에서 서버의 메모리가 손상될 수 있다. 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)을 재현한 결과를 보여준다.






