BLOG
Tracefield · 02
Tracefield · 01
블로그 · 14
Vibe Audit · 04
Vibe Audit · 03
Vibe Audit · 02
Vibe Audit · 01
출판편집자 · 01
StudyTree · 01
SecurityOps · 02
SecurityOps · 01
AI챗봇 · 04
AI챗봇 · 03
AI챗봇 · 02
AI챗봇 · 01
퍼플심 · 04
퍼플심 · 03
퍼플심 · 02
퍼플심 · 01
블로그 · 13
rootscan · 07
rootscan · 06
블로그 · 12
블로그 · 11
블로그 · 10
블로그 · 09
블로그 · 08
블로그 · 07
블로그 · 06
블로그 · 05
블로그 · 04
블로그 · 03
블로그 · 02
블로그 · 01
rootscan · 05
rootscan · 04
rootscan · 03
asmspeak · 03
asmspeak · 02
rootscan · 02
asmspeak · 01
rootscan · 01
웹보안도구 · 02
웹보안도구 · 01
루트캠프 · 02
루트캠프 · 01
All notes 167
CVE_CVE-2025-55182 React2Shell 취약점
1. 개요
핵심 요약은 이렇다.
서버만 써야 할 내부 설계도(실행 지시서)를 외부 사용자가 위조해서 서버에게 실행하게 만든 사고
1.1. 취약점 개요
먼저 기본 정보부터 보면 이렇다.
- 취약점 명칭: React2Shell (React Server Components Deserialization RCE)
- 취약점 유형: 원격 코드 실행(RCE)
- 영향도: Critical (CVSS 10.0)
- CVE: CVE-2025-55182 / CVE-2025-66478
- 발견 일시: 2025-12-03
1.2. 보안 영향
실무 관점에서 보면 영향은 아래 수준이다.
- 인증 우회: 가능
- 원격 코드 실행: 가능
- 데이터 탈취: 가능
- 서버 장악: 가능
- 확산 위험: 높음
2. 취약점 설명
2.1. CVE-2025-55182
React 19의 React Server Components(RSC) / Flight 프로토콜 처리 과정에서 발생하는 인증 불필요(Pre-auth) 원격 코드 실행(RCE) 취약점이다. 영향 범위가 넓고, 익스플로잇이 단일 요청(one-request) 형태로 알려져 CVSS 10.0으로 분류됐다.
핵심 흐름은 이렇다.
- 공격자가 인증 없이 RSC에 악성 데이터가 포함된 HTTP 요청을 보낸다.
- 서버가 유효성 검사를 충분히 하지 않은 채 내부 객체 참조와 실행 경로를 트리거한다.
- 필요하면 그 실행 결과가 다시 공격자에게 전달된다.
이 취약점은 단일 요청만으로도 악용될 수 있다. 공격이 성공하면 서버 장악, 추가 악성코드 설치, 내부망 이동까지 이어질 수 있다.
2.2. CVE-2025-66478
이 CVE는 위 이슈가 Next.js(App Router)에 미치는 다운스트림 영향을 따로 추적하려고 발급됐다. 운영 관점에서는 어떤 버전이 영향을 받고, 어떤 버전에서 수정됐는지를 분리해서 보는 데 의미가 있다.
공개 직후부터 스캐닝과 침투 시도가 넓게 관측됐고, 국가 단위 또는 범죄 조직 단위의 공격 그룹도 빠르게 가세한 것으로 보고됐다.
3. 영향 범위
영향받는 범위는 React 본체와 Next.js 쪽으로 나뉜다.
- React 19(RSC) (CVE-2025-55182)
- react-server-dom-webpack 19.0 / 19.1.0 / 19.1.1 / 19.2.0
- react-server-dom-parcel 19.0 / 19.1.0 / 19.1.1 / 19.2.0
- react-server-dom-turbopack 19.0 / 19.1.0 / 19.1.1 / 19.2.0
- Next.js (CVE-2025-66478)
- Next.js 15.x, 16.x
- 14.3.0-canary.77 이상(카나리)
- App Router에서 RSC를 쓰는 구성이
4. 공격 시나리오
공격 흐름은 아래 순서로 이해하면 된다.
- 공격자는 RSC 또는 Server Action 엔드포인트로 악의적 요청을 보낸다.
- 서버는 그 요청을 Flight 프로토콜 기준으로 역직렬화한다.
- 내부 실행 객체가 외부 입력을 기반으로 생성되거나 참조된다.
- 서버 실행 흐름이 변조되면서 명령 실행이 일어난다.
- 이후 서버 권한 탈취나 악성 페이로드 설치로 이어질 수 있다.
5. POC
POC 과정은 순서대로 보면 된다.
5.1. POC 과정
- https://github.com/msanft/CVE-2025-55182.git 통해 CVE Clone, bun.lock 있지만 도커 사용 목적이라 불필요한 설정은 안 하는 것이 좋겠다고 판단, Node.js+npm 실행으로 진행 결정

- Dockerfile 생성하고 빌드, 실행, 접속 확인




- 서버 외부에서
poc.py코드 실행, 서버 내부 실행 컨텍스트가 외부 입력에 의해 노출됨

5.2. 전체 흐름
POC 전체 흐름은 이렇게 보면 된다.
poc.py가 HTTPPOST요청을 보내고, 헤더를 RSC 요청처럼 위장한다.- 바디에는
Flight chunk데이터를 넣는다. 이chunk는 서로를 참조하고, React 전용 문법을 포함해 서버가 디코딩하는 순간 실행 흐름을 재구성하게 만든다. - 서버는 이를 정상적인 RSC 요청으로 인식하고 Flight 디코더에 넘긴다.
- Flight 디코더는 이 데이터를 서버 내부에서 만든 데이터처럼 처리한다. 이 지점이 핵심 취약점이다.
- 결과는 다시 Flight 응답으로 직렬화되어 돌아온다.
5.3. 서버 내부 흐름
서버 안에서는 아래 순서로 이어진다.
- RSC 실행 파이프라인에 진입한다.
- 내부 객체,
thenable, 에러 처리 로직이 실행된다. redirect()관련 경로로 분기된다.NEXT_REDIRECT에러가 생성된다.- 에러 객체 안에 서버 런타임 컨텍스트(
uid=0등)가 포함된다. - 이 정보가 다시 Flight 응답으로 직렬화되어 반환된다.
5.4. 주의 사항 및 판단 결과
이 PoC를 해석할 때는 아래 점을 분리해서 봐야 한다.
- 이 공격은 곧바로 임의 명령 실행이나 쉘 획득과 같은 개념은 아니다.
- 외부 입력이 서버 내부 함수 실행, 내부 객체 생성, 서버 런타임 정보 접근 같은 경로를 트리거한 사례에 가깝다.
- 즉, 외부 입력이 내부 코드 실행 지점까지 도달했고, 그 결과 내부 상태가 응답으로 새어 나온 것이다.
5.5. 최종 요약
poc.py는 원래 React 서버 내부에서만 써야 할 실행 구조 데이터(Flight)를 외부에서 위조해 보냈고, 서버는 이를 신뢰한 채 내부 코드를 실제로 실행했다.- PoC 응답에 포함된
NEXT_REDIRECT예외와 서버 런타임 컨텍스트(uid=0)는, 외부 조작 요청이 내부 실행 처리 파이프라인에 도달했음을 보여준다. 이 상태는 이후 내부 분기 탐색과 후속 악용 시나리오 설계가 가능한 지점이라는 의미도 가진다.
5.6. 기타 참고 사항
공격자가 이 PoC에서 얻는 정보는 실제 공격 설계의 기초 자료가 된다.
- RSC 서버 여부를 확인해 공격 대상인지 판단할 수 있다.
- 입력값이 파싱 단계에서 막히지 않고 실행 단계까지 갔는지 확인해, 다음 단계 설계 가치가 있는지 볼 수 있다.
uid=0(root), gid=0(root)정보로 서버가root권한으로 동작하는지 확인해 후속 공격의 파급력을 가늠할 수 있다.- 입력 변형 실험을 반복하면서 코드 구조를 바꿔 익스플로잇 개발을 시작할 수 있다.
- 에러 차이를 보면 내부 로직 분기를 추론할 수 있어 오라클 확보 여지가 생긴다.
- 대규모 자동화 공격으로도 확장할 수 있다.
- 다른 내부 객체(
function,promise,constructor계열)로 실행 흐름을 유도할 수 있다. - 내부 참조를 조작하거나 비정상 객체 타입을 만들려는 시도도 가능해진다.
- 비유하면, 금고를 연 것은 아니지만 들키지 않고 금고 구조를 분석할 수 있는 상태와 비슷하다.
추가로 알아두면 좋은 용어는 이렇다.
redirect: 서버 실행 흐름을 멈추고 클라이언트에게 이동을 지시하는 제어 객체다. 실행 파이프라인 깊숙한 곳에서만 생성되므로, 실행 경로 도달 여부를 확인하는 신호로 쓰기 좋다.function: 실제 서버가 무언가를 실행하는 단위다.promise,thenable: 비동기 실행 모델에서 서버가 나중에 처리할 작업을 나타낸다. RSC에서는 매우 자주 등장한다.constructor: 어떤 객체를 만들지 결정하는 생성 틀이다.
6. 대응 및 권고 사항
대응은 단기와 장기로 나눠 보는 편이 낫다.
6.1. 즉각 조치 필요
우선순위가 높은 조치는 아래와 같다.
- React / Next.js 보안 패치 버전으로 업그레이드
- React RSC 19.0.1 / 19.1.2 / 19.2.1
- Next.js 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6 / 15.4.8 / 15.5.7 / 16.0.7
- 패치 후 전체 빌드 및 재배포
- 노출된 서비스의 시크릿 키 재발급
6.2. 장기 대응 방안
구조적으로는 아래 항목을 같이 봐야 한다.
- RSC 입력 검증 강화
- Server Action 접근 제어
- 비정상 요청 로깅 및 탐지 정책 적용
7. 참고 자료
- PoC Code: https://github.com/msanft/CVE-2025-55182
- datadog: https://securitylabs.datadoghq.com/ar...
- microsoft: https://techcommunity.microsoft.com/b...
- aws: https://aws.amazon.com/blogs/security...
- google cloud: https://cloud.google.com/blog/product...
- react2shell: https://github.com/freeqaz/react2shell
- react 패치 PR: https://github.com/facebook/react/pul...
8. 상세 흐름 이해
8.1. RSC는 왜 도입되었는가
- 기존 웹 애플리케이션은 크게 클라이언트 중심 방식/서버 중심 방식이었음

- 서버에서 데이터를 보내면 브라우저가 JS/DOM을 다운로드하고 직접 조립, 출력
- 클라이언트 부담 ↑, 서버 자원(DB/API)에 접근 불가

- 클라이언트 부담 ↑, 서버 자원(DB/API)에 접근 불가
- 서버가 완전히 조립된 페이지를 보내면 브라우저는 출력만
- 서버 부담 ↑, 인터랙션은 클라이언트 JS가 부담
- 이를 해결하기 위해 RSC 도입

- 화면 구성 부품 중 서버에서 처리하기 더 적절한 것만 서버에서 실행
- 서버는 계산과 판단을 담당하고, 브라우저(React)는 조립과 상호작용을 담당
- → 서버는 구조화된 실행 결과를 보내고 브라우저(React)가 이것을 받아 조립한다
- Flight = 구조화된 실행 결과로, 화면의 모양이 아니라 화면을 만드는 방법을 담은 데이터(화면 설계도+데이터 묶음)
- RSC의 암묵적 전제
- Flight는 서버에서만 생성되는, 사람이 만질 수 없는 데이터이므로 신뢰할 수 있는 데이터
- ex) 사용자 입력 데이터 = 고객의 신청서 / Flight 데이터 = 회사 내부의 업무 처리 지시서 → 외부인 접근 X
- 성능, 보안, 구조적으로 매우 좋음
- Flight는 서버에서만 생성되는, 사람이 만질 수 없는 데이터이므로 신뢰할 수 있는 데이터
요약하자면, RSC(React Server Components)는 서버에서 실행된 컴포넌트의 결과와 실행 구조를 Flight라는 내부 전용 포맷으로 전달하는 구조다. Flight는 단순 데이터가 아니라 서버 실행 흐름을 설명하는 설계도에 가깝기 때문에, React는 이를
외부에서 절대 생성되지 않는 내부 데이터라고 가정하고 설계했다.
8.2. 어떻게 신뢰가 붕괴되었는가
- 신뢰 경계 개념과 Flight
- 신뢰 경계란, 이 지점부터 들어오는 데이터는 믿지 않는다고 정한 선
- 클라이언트 브라우저 → 서버 : 신뢰 X
- 서버 내부 메모리 → 서버 코드 : 신뢰 O
- DB 결과 → 서버 코드 : 조건부 신뢰 O
- 이 경계가 명확하면 입력 검증의 지점이 명확해지고 내부 로직이 단순해짐
- 즉, Flight는 서버 내부에서 생성되어 외부로 나가기만 하는 데이터라는 전제 하에
- Flight는 검증 필요가 없으며, 복잡한 보안 로직도 불필요하여 성능, 구조가 매우 좋아짐
- 신뢰 경계란, 이 지점부터 들어오는 데이터는 믿지 않는다고 정한 선
- 클라이언트 → 서버가 정말 신뢰 X인가?
- 서버 액션, 인터랙션 후 서버 재실행, 스트리밍 업데이트 등 클라이언트 → 서버로 보내는 요청 존재
java 외부 입력 HTTP 요청 [클라이언트] -> RSC 요청(HTTP) -> [서버] -> RSC 처리 파이프라인 -> Flight 생성
- 이때 요청과 내부 메시지가 같은 파이프라인으로 작동
- 즉, React 서버가 외부에서 들어온 요청을 내부에서 생성한 Flight와 같은 처리 로직으로 다룸
java [외부 입력 HTTP 요청] -> Flight 디코더 -> [내부 실행 로직]
- 이때 Flight 디코더가 ‘내부 데이터’를 전제로 설계됨
- 그러나 실제로는 외부 사용자가 보낸 데이터가 그대로 들어올 수 있었음
- 이렇게 설계된 이유는?
- 현실적 낙관 : Flight는 일반 사용자가 알기에는 복잡한 데이터 포맷, 직접 만들어 보내기 힘들다는 생각
- 내부 프로토콜이라는 착각 : REST API도 아니고, 공개 포맷도 아니고, 외부 연동용도 아니니 사실상 내부 네트워크라고 인식
- 이렇게 설계된 이유는?
- 보안 관점으로,
HTTP로 들어온 순간 해당 데이터는 공격자가 통제할 수 있는 데이터라는 원칙이 RSC 설계와 충돌- 즉, 검증 대상이 아니라고 설계 단계에서 판단해버린 것 → 검증 개념 자체가 존재하지 않는 설계
8.3. 원격 코드 실행(RCE)으로 이어진 주요 문제
- RSC의 입력 처리 성격의 문제
- 일반적인 서버 입력의 경우 외부 입력은 파라미터 즉, 문자열이나 숫자, JSON이며 검증 실패 시 요청이 거부되고, 성공해도 데이터로만 사용됨
- 데이터 오류나, 권한 문제, 정보 노출 수준의 취약점
- JSON → 객체로 값을 복원하는 역직렬화
- RSC의 경우 외부 입력이 단순 데이터가 아닌
서버가 무엇을 실행할지 결정하는 지시 정보로 취급됨- 역직렬화가 값만 복원하는게 아님
- 실행 구조를 복원하고 컴포넌트 트리를 재구성, 모듈 참조 연결, 서버 액션 호출 경로를 결정
- 즉, Flight의 해석은 서버 내부의 실행 흐름을 재현할 수 있는 단서
- 역직렬화가 값만 복원하는게 아님
- 일반적인 서버 입력의 경우 외부 입력은 파라미터 즉, 문자열이나 숫자, JSON이며 검증 실패 시 요청이 거부되고, 성공해도 데이터로만 사용됨
- 서버가 Flight를 무조건 신뢰하는 문제
- RSC는 이 Flight 데이터를
내부 데이터로 인식하고 모듈 참조 안전, 실행 대상 신뢰, 의도된 함수 호출로 인식 - 이미 검증된 상태라고 가정
- RSC는 이 Flight 데이터를
- Flight의 완결성 문제
- 보통의 RCE를 위해서는 여러 단계와 상태 누적, 인증 우회 등을 거쳐야 함
- 그러나 RCS에서는 Flight 자체가 완결된 실행 지시서로 인식, 상태와 인증, 세션 등의 정보 없이도 실행
- 따라서 단일 요청(one-request)만으로도 RCE가 가능한 중대 취약점이 발생
8.4. 어떤 방식으로 공격이 가능했는가
- 공격자는
RSC 요청처럼 보이는 요청을 보냄- RSC 요청과 동일한 구조의 HTTP
- Flight 데이터처럼 보이는 페이로드
- 서버는 URL도 정상, 헤더도 정상, RSC 요청 조건도 충족된 것으로 판단
- 이 요청은
브라우저 React가 보낸 RSC 요청이다라고 판단 - 서버가 요청을 Flight 디코딩 단계로 요청을 전달하면 데이터의 내부/외부 검증 X
- 이 요청은
- 공격자는 Flight 데이터를 통해 다음과 같은 정보를 조작
- 서버 모듈 참조/실행 경로/인자로 넘길 값
- 서버 실행 흐름 자체 조작 가능
- Node.js 런타임에서 실행 → 파일 시스템 접근 가능 → OS 명령과 논리적으로 가까움
- 임의 코드 실행, 시스템 명령 실행, 악성 페이로드 설치까지 이어짐
8.5. 결론
- 단순 원격 코드 취약점이 아닌 프레임워크 레벨의 취약점
- 개발자의 시큐어 코딩으로도 해결 불가
- 보안 책임자나 개발자의 손을 떠난 취약점
- 대응 난이도가 높고, 영향 범위나 파급력이 강하다
- 프레임워크 버그가 아닌 설계 상의 취약점
- Flight 데이터를 무조건 신뢰 가능한 내부 데이터로 취급한 설계 취약점
- 워크어라운드 없이 업그레이드해야 하는 프레임워크 실행 파이프라인 자체의 문제
- 따라서 현재 패치는 Fligt 디코딩 전 입력의 내/외부 검증과 허용 실행 경로를 검증하고 내부 구조를 외부 요청에서 재구성 불가하도록 → 신뢰 경계를 코드 레벨에서 다시 설정
- 생각해야 할 점
- 네트워크를 타는 순간 그게 내부 포맷이든 뭐든 공격 루트라는 관점 필요
- 서버 실행 경로를 담은 데이터는 무조건 위험하다는 인식 필요
- 프레임워크 선택조차 보안 의사결정에 필요하다는 인식 필요
- 공격자 관점
- 내부 데이터도 네트워크를 타면 공격 대상이며
- REST나 GraphQL같은 공개 API만 보지 않고 내부프로토콜과 전용 직렬화 포맷, 서버-클라이언트간 비공개 메시지까지 분석 대상으로 삼음
- 정리하자면, React2Shell은 공격자에게 프레임워크 내부 데이터와 전용 프로토콜 역시 네트워크를 통해 전달되는 이상 공격 표면이 될 수 있음을 확인시켜 주었다. 향후 공격자는 공개 API뿐 아니라 내부 직렬화 포맷과 실행 지시 데이터까지 분석 대상으로 삼을 것이며, 패치 이후 새롭게 형성된 신뢰 가정과 검증 로직을 우회하는 방향으로 공격을 설계할 가능성이 높다.
- 방어자 관점
- 내부 데이터라 안전하다는 표현 지양
- 침투 경로를 그리는 사고방식 필요
- 정리하자면, 본 취약점은 ‘내부 전용 데이터’라는 표현이 보안상 신뢰 근거가 될 수 없음을 보여준다. 외부 입력이 도달할 수 있는 경로가 존재하는 이상, 해당 데이터는 공격자 관점에서 분석·위조 대상이 된다. 향후 유사 사고를 방지하기 위해서는 데이터의 성격이 아니라, 데이터의 이동 경로와 해석 지점을 기준으로 신뢰 경계를 설정하는 보안 사고 방식이 필요하다.
- 추후 체크포인트
- 내부 전용 데이터가 네트워크를 타는지 점검
- 역직렬화가 일어나는 지점 확인

