React2Shell: 최신 웹 프레임워크를 위협하는 심각한 RCE 취약점 (CVE-2025-55182)
개요
2025년 12월, 웹 개발 생태계를 뒤흔든 심각한 보안 취약점, Reach2Shell이 공개되었다. 이 취약점은 React Server Components와 Flight 프로토콜을 사용하는 애플리케이션에서 발생하며, 공격자는 단 한 번의 HTTP 요청으로 서버에서 임의 코드를 실행할 수 있다. CVSS 점수는 10.0 (Critical)로 평가되었고, 인증 없이 공격이 가능하다는 점에서 그 파급력은 매우 크다.
본 글은 React2Shell(CVE-2025-55182)의 발생 원리와 공격 흐름(React Server Components의 Flight 처리 과정 중 역직렬화 악용)을 정리하고, 취약점 대응 방안을 소개한다.
기술 배경
React Server Components & Server Action
React 18 시점에 React Server Components(RSC)가 실험적으로 도입되었으며, UI를 Server Component와 Client Component로 분리해 서버에서 렌더링한 결과를 클라이언트로 전달하는 모델이 제안되었다. 이를 통해 인터랙션이 필요한 일부만 Client Component로 유지하고 나머지를 Server Component로 두어 클라이언트 사이드의 자바스크립트 번들 크기를 줄이고, 클라이언트의 처리 부담을 낮출 수 있다. 클라이언트에서 서버 측으로 요청할 때 요청 데이터를 직렬화하는 과정이 진행되는데 이 과정에서 React Flight 프로토콜이 활용된다.
React Flight 프로토콜
React Flight 프로토콜은 React 컴포넌트 트리, 데이터, 서버 참조(Server Reference) 등을 서버와 클라이언트 간에 효율적으로 전송하기 위해 설계된 커스텀 직렬화 포맷이다.
Flight 프로토콜은 데이터를 chunk라는 독립적인 단위로 나누어 관리하며, 각 chunk는 고유 ID를 가진다. 데이터 직렬화 시, 특수한 값이나 다른 chunk에 대한 참조는 $ 접두사가 붙은 문자열로 표현된다. 이 참조 시스템은 역직렬화 과정에서 원래의 객체나 값으로 복원된다.
주요 참조 유형은 아래와 같다.
|
접두사 |
유형 |
설명 |
|---|---|---|
| $@ | Promise/Chunk | 특정 ID Chunk에 대한 참조 |
| $B | Blob | 특정 ID Chunk의 Blob 데이터 참조 |
| $Q | Map | 특정 ID Chunk의 Map 객체 참조 |
| $0-9a-f | Chunk 참조 | 16진수 ID를 가진 Chunk에 대한 참조 |
[표 1] Flight 프로토콜 접두사
CVE-2025-55182
이번에 발견된 React Server Components의 치명적인 취약점(CVE-2025-55182, React2Shell)은 Flight 프로토콜 페이로드를 서버 측에서 역직렬화(Deserialization) 시 안전하지 않은 검증으로 인해 발생한다. 즉, 클라이언트에서 서버로 보낸 Flight 프로토콜 페이로드에 대한 검증이 완전하지 않아 발생한 문제이다. 이 공격에 대한 핵심 취약점을 크게 세 가지로 구분할 수 있으며, 전체 공격은 세 취약점의 연계로 완성된다.
1) Fake Chunk 주입
React는 내부적으로 역직렬화된 데이터를 chunk 객체로 관리한다. Chunk 객체는 아래와 같이 ‘status’, ‘value’, ‘reason’, ‘_response’ 속성을 갖는다.

[그림 1] Chunk 속성
서버의 Chunk.prototype.then 처리 흐름에서 공격자가 Chunk처럼 보이는 객체를 주입하고, status가 resolved_model로 처리되는 경로로 유도하면 initializeModelChunk가 호출되는 흐름으로 이어진다.

[그림 2] Chunk.prototype.then
공격자가 이를 악용해 아래 페이로드 일부처럼 페이로드 내부에 fake chunk JSON 객체를 넣어도 initializeModelChunk를 호출한다. 이 때 공격자의 악성 페이로드를 가지고 있는 “_response”: 부분이 그대로 chunk의 _response 속성으로 할당된다.
2) 검증 없는 프로퍼티 경로 순회로 인한 프로토타입 체인 접근/오염
Flight 프로토콜은 콜론(:)으로 구분된 경로를 사용하여 중첩된 객체의 속성에 접근할 수 있다.
문제는 getOutlinedModel 함수 내에서 이 경로를 처리하는 아래 코드에서 발생한다.

[그림 3] 취약한 getOutlinedModel
이 코드는 참조 경로의 각 부분을 객체의 속성 키로 사용하여 순차적으로 값에 접근한다. 이때 parentObject[reference[key]]에 해당하는 속성 이름에 대한 어떠한 검증도 수행하지 않는다. hasOwnProperty를 이용한 확인이 없기 때문에, 공격자는 __proto__나 constructor와 같은 자바스크립트의 ‘매직 프로퍼티’를 경로에 포함시켜 프로토타입 체인을 거슬러 올라갈 수 있다.
이처럼 사용자가 제어하는 입력 값을 통해 객체의 프로토타입을 오염시키는 공격 기법을 프로토타입 오염(Prototype Pollution)이라고 하며, 이것이 전체 공격의 기반이 된다.
3) Function 생성자 가젯 구성으로 코드 실행
Prototype Pollution으로 탈취된 Function 생성자는 주입된 가짜 _response 객체 내의 _formData.get 메서드를 덮어쓰는 데 사용된다. 결과적으로, _response._formData.get은 이제 일반적인 get 함수가 아니라, 문자열을 코드로 실행할 수 있는 Function 생성자 자체가 된다.
“then”:“$B1337” 파싱 과정에서 response._formData.get 함수가 호출되고, 인자로 전달되는 response._prefix는 공격자가 제어하는 코드 문자열(또는 코드 조합 요소)로 악용될 수 있다. 이렇게 생성된 함수 객체는 promise resolution 과정에서 .then() 호출과 동시에 실행된다.

[그림 4] parseModelSring: “$B” 파싱
공격 시나리오

[그림 5] 공격 시나리오 흐름도
해당 취약점이 발생하는 환경을 전제로 공격이 이뤄질 경우 시나리오는 다음과 같다. 공격자는 외부에서 접근 가능한 RSC 요청 처리 경로로 조작된 HTTP POST 요청을 보낸다. 서버는 해당 요청을 정상적인 RSC 처리 흐름으로 받아 Flight 형식의 데이터를 읽어들이고, 공격자가 의도한 형태로 “청크(Chunk)처럼 보이는 데이터”가 내부 처리 과정에 섞이도록 만든다. 즉, 서버가 원래 하려던 “요청 데이터 복원” 과정에 공격자가 준비한 구조물이 자연스럽게 끼어드는 상황을 유도한다.
이후 서버는 참조 경로를 따라 객체의 속성을 찾아가는 과정을 거치는데, 이 경로가 충분히 검증되지 않으면 __proto__나 constructor 같은 키를 이용해 프로토타입 체인 쪽으로 빠져나갈 수 있게 된다. 공격자는 이 지점을 이용해 서버 쪽 객체 상태를 유리하게 바꾼 뒤, 마지막에는 constructor.constructor 같은 방식으로 Function 생성자까지 도달하는 가젯을 성립시켜 자신이 보낸 문자열이 함수로 만들어져 실행되도록 유도한다. 결과적으로 앞에서 정리한 세 가지 결함이 순서대로 연결되면, 단 한 번의 요청 처리 흐름 안에서 서버에서 임의 코드 실행까지 이어질 수 있다.
대응 방안
가장 중요하고 근본적인 해결책은 취약점이 해결된 버전으로 관련 패키지를 즉시 업데이트 후 재배포하는 것이다. 당장 패키지를 업그레이드하고 재배포할 수 없다면 요청 본문에 __proto__ 또는 constructor와 같은 키워드가 포함된 Flight 프로토콜 페이로드를 탐지하고 차단하는 규칙을 적용하는 방법도 있다. 이는 완벽한 해결책은 아니지만, 알려진 공격 패턴을 막는 데 도움이 될 수 있다.
업데이트 및 재배포, 차단 규칙 적용 외에도 위험을 최소화하기 위해, 비즈니스에 필수적이지 않은 서버 액션 기능은 일시적으로 비활성화하는 방법도 고려할 수 있다. 또는 모든 서버 액션 엔드포인트에 대해 강력한 사용자 인증 및 권한 검증 로직을 추가하여 익명의 공격자가 접근하지 못하도록 막아야 한다.
안랩 대응 현황
안랩 제품군의 진단명과 엔진 버전 정보는 다음과 같다.
EDR 진단
- InitialAccess/EDR.Event.M13379(2025.12.17.02)
- InitialAccess/EDR.Event.M13380(2025.12.17.02)
결론
CVE-2025-55182 취약점은 최신 웹 프레임워크의 복잡성이 어떻게 예측하지 못한 새로운 공격 벡터를 만들어낼 수 있는지를 보여주는 중요한 사례이다. 이는 개발자의 비즈니스 로직이 아닌 프레임워크/의존성(라이브러리) 자체의 핵심 로직에 존재하는 고위험 취약점으로, 그 파급력은 생태계 전반에 미친다. React 서버 컴포넌트와 Flight 프로토콜 같은 혁신적인 기술은 개발 편의성을 크게 향상시켰지만, 그 내부 동작의 복잡성 이면에 숨겨진 보안 위협은 매우 치명적이다.
대응을 위해서는 영향을 받는 RSC 관련 패키지 및 이를 포함하는 프레임워크를 즉시 최신 보안 버전으로 업데이트하고, Server Function/Server Action 처리 경로가 외부에 노출된 서비스는 우선순위를 높여 점검해야 한다. 본 취약점에 대한 상세한 기술 분석은 AhnLab ATIP에서 제공하는 “React2Shell 취약점 분석 보고서 (CVE-2025-55182) – AhnLab TIP”을 통해 확인 가능하다.
출처
- https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components
- https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc
- https://gist.github.com/maple3142/48bc9393f45e068cf8c90ab865c0f5f3
- https://github.com/facebook/react/pull/35277/commits/e2fd5dc6ad973dd3f220056404d0ae0a8707998d?diff=split&w=0
- https://www.cve.org/CVERecord?id=CVE-2025-55182