React (RSC) 익스플로잇이 실제이며 엔지니어링 팀에 피해를 주고 있다

발행: (2026년 1월 9일 오전 01:11 GMT+9)
16 분 소요
원문: Dev.to

Source: Dev.to

React (RSC) 악용이 실제이며 엔지니어링 팀에 피해를 주고 있습니다

소개

웹 엔지니어링 분야에서 일한다면, 2026년으로의 전환은 새로운 기능들에 의해 정의된 것이 아니라, 단 하나의 끔찍한 깨달음에 의해 정의되었습니다: 클라이언트와 서버 사이의 경계가 깨졌습니다.

12월에, React2Shell (CVE‑2025‑55182)은 React Server Components에서 중요한 원격 코드 실행(RCE)을 드러냈습니다. 팀들이 패치를 적용하자마자, 동일한 서브시스템에서 두 개의 고위험 익스플로잇이 추가로 등장했습니다. 이것이 최종적인 기술 사후 분석입니다.

“React2Shell” RCE (CVE‑2025‑55182)

이 취약점(CVSS 10.0)이 왜 그렇게 파괴적이었는지 이해하려면, 먼저 그것이 파괴한 메커니즘인 React Flight Protocol을 이해해야 합니다.

수년간 React 개발자들의 사고 모델은 간단했습니다: React는 브라우저에서 UI를 렌더링하고, API(REST/GraphQL)는 데이터를 가져옵니다. 서버와 클라이언트는 명확한 네트워크 경계로 구분된 별개의 세계였습니다.

React Server Components(RSC)는 그 경계를 지워버렸습니다.

React Flight Protocol 다이어그램

RSC 세계에서는 서버가 클라이언트에 HTML을 보내지 않습니다. 대신 Flight라는 독점 직렬화 포맷을 스트리밍합니다. 이 스트림에는 다음이 포함됩니다:

  • UI 컴포넌트 설명
  • 직렬화된 데이터
  • 데이터를 해결하는 Promises

React2Shell 작동 방식

React2Shell 은 일반적인 SQL‑injection이나 XSS가 아니었습니다. 직렬화 해제기를 노린 논리 남용이었습니다. 공격자는 특정 Flight 페이로드를 포함한 HTTP POST 요청을 만들었습니다. 이러한 바이너리와 유사한 스트림은 유효한 컴포넌트 트리를 흉내 내면서 Thenable 객체(가짜 Promise)를 숨겼습니다.

StepDescription
Injection공격자는 악의적인 __proto__ 키를 포함한 직렬화된 객체를 전송합니다.
Deserialization서버가 스트림을 파싱하고 가짜 Promise를 해결하려 시도합니다.
Prototype Pollution정화가 부족해 __proto__ 가 실행 중인 Node.js 프로세스의 Object.prototype 을 덮어쓸 수 있습니다.
Gadget Chain수정된 프로토타입이 내부 호출을 트리거하여 Function 생성자에 도달합니다.
ExecutionFunction 에 대한 접근 권한으로 require('child_process').exec(...) 와 같은 임의 코드를 즉시 컴파일하고 실행할 수 있습니다.

Next.js에 미친 영향

Next.js App Router가 기본적으로 RSC를 활성화하기 때문에 모든 Next.js 애플리케이션(버전 15.x, 16.x 및 canary 빌드)은 바로 취약했습니다. 해킹당하기 위해 버그가 있는 Server Action을 작성할 필요도 없었고, Server Components를 명시적으로 사용할 필요도 없었습니다. 애플리케이션이 react-server-dom-webpack을 가져오면 이러한 Flight 페이로드를 수신 대기하고 있었습니다.

클라이언트‑서버 컴포넌트 상호작용 다이어그램

크레딧: 이미지 제공: Next.js

DevOps 악몽

WAF 맹점

표준 웹 애플리케이션 방화벽(WAF)은 SQL 인젝션(' OR 1=1)이나 스크립트 태그(<script>)와 같은 고전적인 공격을 탐지하도록 훈련되어 있습니다. 그러나 React Flight의 독점 텍스트 형식을 검사하도록 훈련되지 않았기 때문에, 악성 페이로드가 초기에는 Cloudflare와 AWS WAF 규칙을 그대로 통과했습니다.

공급망 지옥

취약점은 node_modules 깊숙한 곳에 존재했습니다. 코드를 단순히 “수정”할 수 없었습니다. Vercel과 React 팀이 패치된 바이너리를 출시할 때까지 기다린 뒤, 모든 마이크로서비스를 다시 빌드하고 재배포해야 했습니다.

여진 (DoS와 유출)

엔지니어링 팀이 RCE 패닉에서 회복하고 있던 중, 보안 커뮤니티는 기반 구조에 더 많은 균열을 발견했습니다. 2025년 12월 11일, React 팀은 세 개의 추가 CVE에 대한 새로운 권고를 발표했습니다.

이것들은 RCE는 아니지만 운영상 파괴적이며 현재 직렬화 구현의 취약성을 강조합니다.

1. 서비스 거부 (DoS) (CVE‑2025‑55184)

심각도: 높음 (7.5/10)

이 취약점을 이용하면 공격자가 단일 요청만으로 인프라를 “동결”시킬 수 있습니다.

메커니즘

Flight 프로토콜은 데이터 청크가 다른 청크를 참조하도록 허용합니다. 연구원들은 페이로드에 순환 의존성을 만들 수 있음을 발견했습니다:

  1. 청크 A가 청크 B를 참조합니다.
  2. 청크 B가 청크 A를 참조합니다.

React 디시리얼라이저가 이 구조를 해석하려 할 때 무한 동기 루프에 빠집니다.

Node.js event‑loop blockage illustration

인프라에 미치는 영향
Node.js는 단일 스레드이기 때문에, 이 무한 루프는 이벤트 루프를 차단하여 전체 프로세스가 응답하지 않게 됩니다. 일반적인 Next.js 배포 환경에서는 하나의 손상된 요청만으로 전체 서버 또는 컨테이너가 다운될 수 있어, 전체 플릿에 걸친 서비스 거부가 발생합니다.

2. 소스 코드 노출 (CVE‑2025‑55185)

심각도: 중간 (6.2/10)

Flight 디시리얼라이저의 결함으로 공격자는 내부 모듈 식별자를 요청할 수 있었으며, 이는 오류 메시지에 반영되었습니다. 이와 프로토타입 오염 버그를 연계하면 서버‑사이드 소스 코드 조각을 가져와 비즈니스 로직 및 잠재적인 API 키가 유출될 수 있습니다.

3. 인증되지 않은 Server‑Action 호출 (CVE‑2025‑55186)

심각도: 높음 (7.8/10)

Next.js 15에 도입된 Server Actions는 클라이언트에서 CSRF 토큰과 함께 호출되어야 합니다. 이 취약점은 요청 본문에 특수하게 조작된 Flight 페이로드가 포함될 경우 토큰 검사를 우회하여, 인증되지 않은 사용자가 임의의 서버‑사이드 로직(예: 데이터베이스 쓰기, 이메일 전송)을 트리거할 수 있게 합니다.

교훈 및 완화 방안

영역권고 사항
Patch ManagementReact와 Next.js를 버전 ≥ 16.0.3(또는 최신 보안 패치가 적용된 릴리스)으로 고정합니다. 승인된 바이너리를 강제하기 위해 내부 미러를 사용합니다.
WAF RulesWAF 서명을 확장하여 바이너리 Flight 페이로드를 검사합니다. 비정상적으로 큰 __proto__ 필드나 반복되는 청크 참조를 찾아냅니다.
Runtime Hardening프로덕션에서는 Function 생성자를 비활성화합니다(--disable-features=FunctionConstructor). 동적 코드 실행이 필요할 경우 vm 샌드박싱을 사용합니다.
ObservabilityFlight 역직렬화 지연 시간 및 청크‑참조 깊이에 대한 메트릭을 추가합니다. DoS 시도를 나타낼 수 있는 급증에 대해 알림을 설정합니다.
Supply‑Chain Audits모든 의존성 업그레이드 후 npm audityarn audit를 실행합니다. React‑특화 공격 표면을 이해하는 Snyk와 같은 도구 사용을 고려합니다.
Zero‑Trust Deployments각 Next.js 서비스를 사이드카 뒤에 배치하여 들어오는 Flight 스트림을 스키마와 검증한 뒤 Node.js 프로세스로 전달합니다.

마무리 생각

React2Shell 사가는 클라이언트‑서버 경계는 더 이상 안전한 추상화가 아니다—이는 공격자가 무기로 사용할 수 있는 가변적인 표면이다. 2026년이 깊어감에 따라, 팀은 직렬화 포맷(예: Flight)을 REST/GraphQL API에 적용하는 것과 동일한 엄격함으로 다루어야 한다: 엄격한 스키마 검증, 철저한 퍼즈 테스트, 그리고 지속적인 모니터링.

경계를 늦추지 말고, 의존성을 최신 상태로 유지하며, “서버‑전용” 코드가 자동으로 안전하다고 가정하지 마라.

1. Denial‑of‑Service (CVE‑2025‑67779)

Severity: Critical (9.8/10)

Impact:

  • CPU Spike: CPU가 즉시 100 %까지 급증합니다.
  • Request Drops: 서버가 다른 모든 사용자에 대한 응답을 중단합니다. 헬스 체크가 실패합니다.
  • Cluster Destabilization: Kubernetes에서 liveness probe가 실패하여 파드가 재시작될 수 있습니다. 공격자가 이러한 요청을 지속적으로 스트리밍하면 전체 클러스터가 CrashLoopBackOff 상태에 빠져 애플리케이션이 다운됩니다.

Note: 초기 수정이 불완전하여 CVE‑2025‑67779(“수정에 대한 수정”)가 발생했으며, 이로 인해 DevOps 팀은 2주 안에 세 번째 패치를 적용해야 했습니다.

2. Source‑Code Leak (CVE‑2025‑55183)

Severity: Medium (5.3/10)

Why it matters:
이는 React 생태계에서 가장 당혹스러운 취약점이라고 할 수 있습니다. 공격자가 서버를 속여 소스 코드를 클라이언트에 반환하도록 만들 수 있습니다.

Mechanism

이 공격은 JavaScript 문자열 강제 변환에 의존합니다. 서버 액션이 서버 런타임 내부의 함수에 대해 암묵적으로 .toString()을 호출하는 객체를 반환하면, V8의 기본 동작이 해당 함수의 소스 코드를 반환합니다.

“Secrets” Risk

개발자는 use server 파일 안의 코드는 비공개라고 가정하는 경우가 많습니다. 예를 들어 다음과 같이 작성할 수 있습니다:

// DO NOT DO THIS
const STRIPE_KEY = "sk_live_12345";
export async function purchase() { /* … */ }

보통 상황에서는 STRIPE_KEY가 서버에 머무릅니다. 그러나 CVE‑2025‑55183이 존재하면 공격자는 반환값의 직렬화를 조작해 함수의 스코프를 덤프할 수 있어, 하드코딩된 API 키, 내부 주석, 데이터베이스 스키마 정보 등이 노출될 위험이 있습니다.

즉각적인 조치 계획

Next.js App Router (v13.3+) 또는 React 19를 사용 중이라면 아래 단계를 즉시 실행하십시오.

“즉각적인” 업데이트

시맨틱 버전 범위에 의존하지 마세요. 논의된 모든 CVE를 명시적으로 해결하는 릴리스로 의존성을 고정하십시오.

npm install react@19.0.2 react-dom@19.0.2 next@15.1.3
# 깊게 중첩된 의존성 확인
npm list react-server-dom-webpack

react-server-dom-webpack가 최소 버전 19.0.2인지 확인하세요.

속도 제한 적용

DoS 공격은 공격자에게 비용이 적습니다. 인프라 수준(Nginx, Cloudflare, AWS WAF 등)에서 모든 라우트, 특히 POST 요청에 대해 공격적인 속도 제한을 적용하십시오.

비밀 정보 감사

서버 코드가 유출될 수 있다고 가정하십시오. app/ 디렉터리를 스캔하십시오. .ts 또는 .js 파일에서 API 키, 하드코딩된 비밀번호, 내부 IP 주소 등을 발견하면 즉시 환경 변수로 옮기십시오.

결론

React Server Components는 웹의 강력한 진화이지만, **“React2Shell”**은 이 힘이 무시무시한 새로운 공격 표면을 만든다는 것을 보여주었습니다. Flight 프로토콜은 복잡하고, 우리가 보았듯이 복잡성은 보안의 적입니다.

읽어 주셔서 감사합니다! 이 글이 도움이 되었다면, 혜택을 받을 수 있는 다른 사람들과 공유해 주세요. 다른 블로그 글도 자유롭게 살펴보시고 소셜 미디어에서 저를 팔로우해 주세요.

Back to Blog

관련 글

더 보기 »

TWD Tip: Auth0 훅 스텁 및 React 모듈 목업

Background Authentication은 현대 앱에서 테스트하기 가장 까다로운 기능 중 하나입니다. Auth0와 같은 도구는 특히 React와 함께 사용할 때 큰 도움이 되며, such as ...와 같은 hooks를 제공합니다.

맞춤 인증 흐름 및 구현 이해

Custom Auth Flow 구현 최근 나는 Custom Auth Flow를 정말 이해하려고 노력했고, 그 구현이 실제로 어떻게 작동하는지 알아보려고 했습니다. 그래서 나는 다시 구축하기 시작했습니다.