본문으로 건너뛰기
보안 12분 읽기

React Server Components(RSC) 취약점: 'React2Shell' 분석과 대응

React 서버 컴포넌트에서 발견된 심각한 RCE 취약점(CVE-2025-9281). 16만 개의 서버가 위험에 노출되었습니다. 기술적 원인 분석과 긴급 보안 패치 가이드.

강지원
보안 컨설턴트
2025년 12월 20일
React Server Components(RSC) 취약점: 'React2Shell' 분석과 대응
React Server Components(RSC) 취약점: 'React2Shell' 분석과 대응 / 이미지 출처: Unsplash

2025년 12월 3일, 전 세계 프론트엔드 생태계를 뒤흔든 심각한 보안 취약점이 공개되었습니다. 일명 ‘React2Shell’이라 불리는 이 취약점(CVE-2025-9281)은 React Server Components(RSC)의 직렬화 과정에서 발생하는 원격 코드 실행(RCE) 문제입니다.

보안 컨설턴트로서, 현재 확산 중인 이 취약점의 기술적 원인과 긴급 대응책을 심층 분석합니다. 현재 165,000개 이상의 서버가 이 공격에 노출되어 있는 것으로 파악됩니다.

1. 취약점 개요 (Severity: Critical 9.8/10)

이 취약점은 해커가 특수하게 조작된 JSON 페이로드를 React 서버로 전송할 때 발생합니다. RSC가 클라이언트 요청을 처리하는 과정에서, 검증되지 않은 입력값이 서버 내부의 실행 컨텍스트로 전달되어 임의의 시스템 명령어를 실행할 수 있게 만듭니다.

1.1 영향받는 버전

  • react-server-dom-webpack: 19.0.0 ~ 19.2.0 미만 버전
  • next: 15.0.0 ~ 16.0.1 미만 버전 (App Router 사용 시)

1.2 공격 시나리오

  1. 정찰: 공격자는 공개된 React 앱의 엔드포인트(/_next/static/...)를 스캔하여 RSC 사용 여부를 확인합니다.
  2. 주입: __rsc_action_id 파라미터나 POST 바디에 악성 코드가 포함된 직렬화 데이터를 주입합니다.
  3. 실행: 서버가 이를 역직렬화하는 순간, 공격자가 심어둔 쉘 스크립트가 실행됩니다.
  4. 장악: 공격자는 서버의 환경 변수(AWS 키, DB 접속 정보)를 탈취하거나, 리버스 쉘을 열어 서버를 장악합니다.

2. 기술적 심층 분석: Flight 프로토콜의 허점

문제의 핵심은 React가 서버 컴포넌트와 클라이언트 컴포넌트 간의 데이터를 직렬화하는 방식인 ‘Flight’ 프로토콜 구현체에 있었습니다.

2.1 취약한 코드 패턴 (Simulated)

RSC는 클라이언트에서 서버로 함수나 객체를 전달할 때, 보안을 위해 $ 접두사가 붙은 특수 키를 사용합니다. 하지만 특정 버전의 파서가 프로토타입 오염(Object Prototype Pollution)을 제대로 방어하지 못했습니다.

// 취약한 React 내부 코드 예시 (단순화됨)
function resolveModel(response, id, model) {
  // 사용자의 입력을 적절한 검증 없이 객체 병합 수행
  if (model && model.$$typeof === REACT_ELEMENT_TYPE) {
     const props = model.props;
     // 공격자가 '__proto__'를 통해 오염시킨 객체가 실행될 수 있음
     if (props && props.dangerouslySetInnerHTML) {
        // 여기서 RCE 트리거
        sanitize(props.dangerouslySetInnerHTML.__html);
     }
  }
}

공격자는 model.props에 시스템 명령어를 실행하는 객체를 위장하여 주입합니다. React 팀은 초기 설계 시 이러한 형태의 공격 벡터를 예상하지 못했으나, AI를 활용한 퍼징 도구들이 이 미세한 틈새를 찾아냈습니다.

2.2 PoC (Proof of Concept)

다음은 공격 페이로드의 개념 증명입니다. (실제 악용 불가능하도록 수정됨)

{
  "$$typeof": "Symbol(react.element)",
  "type": "div",
  "props": {
    "dangerouslySetInnerHTML": {
      "__html": {
        "toString": {
          "$func": "return process.mainModule.require('child_process').execSync('cat /etc/passwd').toString()"
        }
      }
    }
  }
}

서버가 이 JSON을 파싱하고 렌더링을 시도하는 순간, toString 메서드가 호출되면서 execSync가 실행됩니다.

3. 피해 현황 및 확산 타임라인

12월 10일 기준, 구글 위협 인텔리전스 팀의 보고서에 따르면 전 세계적으로 약 64만 개의 도메인이 잠재적 위협 대상입니다.

  • 12월 3일: 익명의 보안 연구자가 React 팀에 취약점 제보.
  • 12월 5일: 다크웹 포럼에 ‘React2Shell’ 익스플로잇 키트 등장 ($500).
  • 12월 7일: 핀테크 스타트업 A사, 서버 침해 사고 발생. 고객 데이터 유출 의심.
  • 12월 8일: Vercel 및 React 팀, 긴급 보안 패치 배포.

한국에서도 약 12,000개의 서버가 취약한 상태로 노출되어 있으며, 주요 타겟은 핀테크 스타트업, 이커머스 플랫폼, 그리고 개인정보를 다루는 SaaS 기업입니다.

4. 긴급 대응 가이드: 지금 당장 해야 할 일

이 글을 읽는 즉시 다음 조치를 취해야 합니다. “나중에”는 없습니다.

4.1 패치 적용 (최우선)

가장 확실한 방법은 라이브러리를 최신 버전으로 업데이트하는 것입니다.

# npm 사용자
npm audit fix --force
npm install next@latest react@latest react-dom@latest

# yarn 사용자
yarn upgrade next react react-dom

패치 버전: next@16.0.2 이상, react@19.2.1 이상

4.2 WAF(웹 방화벽) 규칙 업데이트

패치를 즉시 적용하기 어려운 레거시 시스템의 경우, WAF단에서 공격 패턴을 차단해야 합니다.

  • 차단 규칙: HTTP 요청 헤더나 바디에 __proto__, constructor, process.env, /bin/sh 같은 문자열이 포함된 패턴을 정규식으로 차단하십시오.
  • Cloudflare/AWS WAF: 이미 관리형 규칙(Managed Rules)에 ‘React2Shell’ 차단 시그니처가 추가되었습니다. WAF를 활성화하고 있는지 확인하십시오.

4.3 서버 로그 모니터링 및 침해 지표 확인

이미 침투했을 가능성을 배제할 수 없습니다. 다음 지표를 확인하십시오.

  1. 이상 트래픽: 서버가 평소에 통신하지 않던 낯선 IP(특히 동유럽이나 제3국)로 아웃바운드 연결을 시도하는지 확인.
  2. 프로세스: node 프로세스의 자식 프로세스로 sh, bash, curl, wget 등이 실행된 기록이 있는지 확인.
  3. 파일 변경: /tmp 디렉토리에 의심스러운 실행 파일이 생성되었는지 확인.

5. 근본적인 보안 대책: Zero Trust

이번 사태는 ‘프레임워크가 알아서 해주겠지’라는 안일한 생각이 얼마나 위험한지 보여줍니다.

  1. 입력값 검증: 프레임워크가 무엇을 하든, 비즈니스 로직 단에서 모든 입력값을 철저히 검증(Zod, Yup 등 활용)해야 합니다.
  2. 최소 권한 원칙: 웹 서버 프로세스가 root 권한으로 실행되어서는 안 됩니다. 공격자가 RCE에 성공하더라도, 권한이 제한된 컨테이너 내부라면 피해를 최소화할 수 있습니다.
  3. 의존성 스캔: CI/CD 파이프라인에 Snyk이나 Trivy 같은 보안 스캔 도구를 연동하여, 배포 전에 취약한 패키지를 감지해야 합니다.

마치며

React Server Components는 훌륭한 기술이지만, 서버와 클라이언트의 경계가 흐려지면서 새로운 공격 표면을 열었습니다. 보안은 속도가 아니라 방향입니다. 지금 당장 package.json을 확인하고 업데이트 버튼을 누르십시오. 165,000번째 피해자가 되지 않기를 바랍니다.

전체 댓글 0

댓글을 불러오는 중입니다...

공유하기

관련 아티클