개요
2025년은 온갖 개인정보 유출 사건들이 계속 터지며 보안으로 정신없는 한 해 였는데, 연말기념 거대 이벤트가 터져버렸다. 바로 React2Shell로 불리고 있는 CVE-2025-55182**이다. 무려 1. 인증없이, 2. 원격으로, 3. 코드 실행 RCE 가 가능하단다.. 이 무슨 eval같은 소리인가
이 문제는 Lachlan Davidson 이 최초 제보하였고, Meta가 이를 패치한 날 해당 개념 증명에 대한 코드를 Github에 공개하였다. 이를 기반으로 RSC에서 어떤 취약점이 있었는지 분석해보았다.
CVE(Common Vulnerabilities and Exposures)
공개적으로 알려진 취약점을 의미하며, CVE-발생연도-취약점번호 형식으로 구성된다.
CVSS(Common Vulnerability Scoring System)
취약점의 심각도를 평가하는 시스템으로, 0.0부터 10.0까지의 점수를 부여한다.
RCE(Remote Code Execution)
원격 코드 실행. 공격자가 원격에서 서버의 운영체제 명령을 실행할 수 있는 심각한 취약점.
대응 방안
이 글을 보고 있는데 아직 서비스중인 Next.js App Router 프로젝트에 hotfix 를 진행하지 않았다면, 아래 링크에서 서비스중인 Next.js 버전이 위험한지 확인해보자.
해당 취약점을 해결하는 방법은 Next.js, React 버전을 업데이트 하는 방법 뿐이다.
https://nextjs.org/blog/security-update-2025-12-11
2025년 12월 11일 기준, 2개의 보안 취약점이 추가되었다. 만약 이전에 hotfix를 진행했다면 한번 더 진행해야 한다.
- CVE-2025-55182 기존 React2Shell 취약점
- CVE-2025-55183 5.3 / MEDIUM / Server Function 의 컴파일된 소스 코드 노출 취약점
- CVE-2025-55184 7.5 / HIGH / Server Function의 DoS 취약점. 서버에 무한 루프를 발생시키고 HTTP 요청을 처리하지 못하게 만들 수 있음
해당 링크는 위험한 버전과 취약점이 해결된 버전이 정리되어 있다.
해당 취약점은 인프라 레벨에서 혹은 코드 레벨에서 방어가 불가능한 공격 기법이다. 반드시 hotfix가 되어야한다.
테스트를 위한 환경 구성
문제가 되었던 next.js를 설치한 후 docker로 배포하였다.
- 해당 Repo: https://github.com/kdh379/react2shell-poc
- 제보자가 공개한 POC Code: https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc/blob/main/01-submitted-poc.js
- 더 star 많은 POC Code: https://github.com/msanft/CVE-2025-55182/blob/main/poc.py
star가 더 많은 코드를 기반으로 작성하였다. 더 단순한데도 작동하였다.
1. 공격은 어떻게 일어났을까?
공개된 개념증명 코드를 바탕으로 어떤 일이 발생했는지 단계별로 추론해봤다.
1. Server Action의 트리거
Next.js는 Next-Action 헤더를 감지하면 Server Action 요청으로 인식하고 이를 처리하기 위해HTTP Body(FormData)를 파싱(역직렬화)한다. 해당 로직은 프레임워크 내부에서 자동으로 일어나므로 개발자가 별도로 코드를 작성하지 않더라도 공격 포인트가 노출된다.
2. 악의적인 payload 구성
해당 코드가 https://github.com/msanft/CVE-2025-55182/blob/main/poc.py 의 일부 내용이다.
3. 프로토타입 오염 ( Prototype Pollution )
Prototype Pollution 공격자가 객체의 프로토타입 속성을 추가하거나 수정할 수 있는 취약점. 이를 통해 XSS 공격에 노출될 수 있다. React2Shell에선 서버에서 RCE가 발생했다.

공격의 핵심은 JavaScript의 객체 관리 구조를 악용하는 것이다.
JavaScript의 모든 객체는 __proto__를 통해 상위 객체(프로토타입)와 연결 된다. 이는 MDN에도 명시된 프로토타입 체인으로 문서로 알 수 있다. 공격자는 payload에 "$1:__proto__:then" 과 같은 값을 포함시켜서, 역직렬화 과정에서 생성되는 객체의 프로토타입을 조작한다.
-
Next.js의 역직렬화 과정에서
$1:__proto__:then은 특별한 의미를 갖고 있다고 추정된다. -
$1은 FormData의 두번째 항목인formData.append('1', '"$@0"')을 가리키는 값이다. -
__proto__를 통해 JavaScript 객체의 프로토타입 체인에 접근합니다. -
결과적으로
then속성을 덮어쓰게 된다. -
정상적인 경우엔 데이터는 단순히 값으로 저장되겠지만
-
공격이 목적이라면
Object.prototype.then과 같은 핵심 속성을 덮어씌운다.
4. Thenable을 이용한 JS 실행 순서 납치
Next.js는 비동기 처리를 위해 객체가 then 메서드를 가지고 있는지 확인하는 것으로 추정된다. (Promise 호환성 체크)
- 공격자가 주입한
then속성이 존재하므로, 시스템에서 이 객체를 Promise 처럼 취급한다. - 시스템은 이 가짜
then함수를 실행하려고 시도한다. - 이 때
then의 값으로Function생성자(constructor:constructor)를 참조하게 만든다.
이 내용을 기반으로 Function 생성자를 통해 코드를 실행시킨다.
$1은 객체를 참조.constructor는 해당 객체의 생성자 함수.constructor.constructor는Function생성자를 의미_prefix에 있는 문자열이Function생성자를 통해 실행 가능한 코드로 변환됨
이제 __prefix에 있는 문자열은 서버에서 실행되는 코드가 된다.
요약하면 아래와 같다.
- 안전하지 않은 역직렬화
- 프로토타입 오염
- Promise 로직 트리거
- Function 생성자 호출
- 원격 코드 실행(RCE)
PoC
Repo: https://github.com/kdh379/react2shell-poc
보안 패치가 이뤄지지 않은 Next.js 16.0.6 을 설치한 후, Docker로 배포하였다.
테스트를 위해 .env 파일을 Docker Container 내부에 생성했다.
docker terminal env screenshot

docker terminal screenshot

그리고 Mac OS Terminal 에서 PoC 코드를 실행해보자.
배포 경로에 포함된 환경변수를 출력하는 shell 스크립트를 실행해보았다.
mac os terminal screenshot

정말로 sh 스크립트가 실행됐다. 물론 다른 shell 스크립트도 무리없이 실행되었다..
이후 Docker Terminal엔 아래와 같은 로그가 남겨지게 되었다.
docker terminal screenshot

보안 패치가 이뤄진 버전으로 빌드 후 다시 테스트 해보았다.
docker terminal screenshot

mac os terminal screenshot

이후엔 사진과 같이 Server action not found. 응답이 나오며 공격이 실패하였다.
방어할 수 있었나?
코드 레벨에선 어떻게 할 방법이 없지만, WAF (Web Application Firewall)을 이용하여 의심스러운 헤더(Next-Action)과 비정상적인 Body 조합 ( __proto__, child_process )를 차단하는 규칙을 적용시키면, 완벽 방어를 보장하진 않지만 최소한의 방어책은 될 것이다.
Vercel 배포 환경의 경우 CVE 발표 이전에 미리 WAF 규칙을 설계해두었다고 한다. 추가로 새롭게 식별된 공격 패턴에 대해 지속 대응하고 있다고 한다.(vercel.com react2shell#vercel-waf-protection) 아주 다행인 사항이지만, 한편으론 Next.js와 Vercel의 강결합에 대해 부정적 시선이 많았는데 이번 기회에 더욱더 강한 결합을 보여주고 있는 것 처럼 보여진다..
마무리
React2Shell 취약점은 "편리한 기능(서버 접근 가능, Server Action 자동 직렬화)"이 "보안 위협"이 될 수 있음을 보여주는 전형적인 사례였다. 프레임워크가 제공하는 '마법'뒤에 React2Shell과 같은 취약점들이 발생할 수 있다.