CVE-2025-29927

2026. 1. 13. 16:44·Web Study
반응형

CVE-2025-29927

명칭: Next.js Middleware 인증/권한 우회

Next.js에서 미들웨어(Middleware)에만 의존해서 인증/권한 체크를 해둔 경우, 공격자가 특정 내부용 헤더를 흉내 내서 미들웨어 실행을 ‘건너뛰게’ 만들고 보호된 페이지에 접근할 수 있는 취약점입니다.


미들웨어(Middleware)가 뭐지?

Next.js 문서 기준 Middleware는 요청이 라우트(페이지/핸들러)에 도착하기 전에 실행되는 코드라고 정의가 되어있습니다.

 

무슨 일을 하는데?

  1. 로그인했는지 확인 → 안 했으면 /login으로 보내기
    • 인증 쿠키/토큰이 없으면 NextResponse.redirect(new URL('/login', req.url)) 같은 식으로 로그인으로 보냄
  2. 특정 권한(관리자)인지 확인 → 아니면 403
    • 로그인은 했어도 role이 admin이 아니면 return new Response('Forbidden', {status:403}) 등으로 차단
    • “접근 제어(Authorization)”를 미들웨어에 넣는 대표 사례입니다.
  3. 국가/언어별 리다이렉트 처리
    • 예: Accept-Language, GeoIP 기반으로 /en, /ko로 보내거나, 특정 국가에서만 페이지 노출
  4. 보안 헤더 추가
    • CSP, X-Frame-Options, HSTS 같은 헤더를 응답에 추가해 전역 보안 정책을 적용

서브리퀘스트(subrequest)

미들웨어는 렌더링(페이지 처리)과 분리된 별도 프로세스/단계에서 동작합니다.

Next.js는 무한 재귀(루프)를 막기 위해 내부적으로 x-middleware-subrequest 헤더를 사용합니다.

 

쉽게 말해,

  • 사용자가 /admin 요청
  • 미들웨어가 뭔가 확인하다가 내부적으로 다시 앱의 다른 URL을 한번 더 요청(혹은 rewite)
  • 이때 미들웨어가 또 그 요청을 잡아 내부 요청을 만들고.. 와 같은 루프가 생길 수 있음
  • 그래서 '이건 내부에서 만든 서브리퀘스트다(미들웨어 이미 한번 실행했다)'라고 표시하려고 만든 내부용 헤더가
    x-middleware-subrequest 

x-middleware-subrequest

이 헤더는 개발자가 이 헤더를 "직접 작성해서 클라이언트에 보내라고" 만든 것이 아닙니다.

원래 의도는 Next.js 내부에서 자동으로 붙이는 내부 신호입니다.

 

정상 설계 의도

  • 라우터/서버는 요청을 받을 때
    • "이 요청이 사용자가 처음 보낸 것인가?"
    • "이 요청이 미들웨어가 내부에서 만든 서브리퀘스트인가?"

를 구분해야 합니다.

 

그런데 여기서 Next.js가 그 구분을 x-middleware-subrequest 헤더 하나에 의존을 해서 문제가 발생합니다.

즉, 외부 사용자가 그 헤더를 마음대로 붙여도 "내부 요청"으로 오해하고 미들웨어 실행을 스킵합니다.

 

따라서 미들웨어에 넣어둔 인증/권한 체크가 무력화될 수 있습니다.


공격 방식

Background

예를 들어, 요청이 이렇게 들어온다고 가정해 봅시다.

x-middleware-subreqeust:middleware:middeware:middleware

HTTP 관점에서는 이 값은 문자열 한 덩어리입니다.

 

그런데 Next.js 내부 코드에서 이 문자열을 : 로 split 해서 리스트로 만들었습니다.

  • 헤더 문자열:"middleware:middleware:middleware"
  • split 결과: ["middleware", "middleware", "middeware"]

Next.js 내부에서는 재귀 제한값(기본 5) 같은 로직이 존재했었습니다.

Next.js는 x-middleware-subreqeust를 split 한 리스트에서 "현재 미들웨어 이름이 몇 번 등장하는 세어 재귀를 판단" 했습니다.

 

그래서 공격 흐름은 이렇습니다

  1. 헤더 값을 가져온다
  2. : 로 split 한다
  3. 리스트에서 미들웨어 이름이 같은 값이 몇 번 있는지 카운트
  4. 그 횟수가 MAX_RECURSION_DEPTH(기본 5) 이상이면 루프 방지 목적으로 미들웨어 실행을 중단하고 다음 단계로 넘어감
x-middleware-subreqeust:middleware:middeware:middleware:middleware:middleware

 

##그럼 x-middleware-subrequest : 5는 안 되나요?

먼저, Next.js는 이 헤더를 숫자로 해석하지 않습니다.

문자열을 split 해서 리스트로 만들고, 그 안에 미들웨어 이름이 몇 번 등장했는지를 세기 때문에

x-middleware-subrequest: 5를 해도 ["5"]가 되기에 카운트가 되지 않습니다.


해결 방안

외부 요청 헤더 차단

: 외부 요청에서 x-middleware-subrequest 가 들어오는 것을 차단/제거

 

이중 검증

: 중요한 데이터/API는 라우터/핸들러/백엔드 등에서도 세션/권한을 다시 확인하는 방식 적용

 

실제 패치?

1) 프로세스(세션)마다 랜덤 ID 생성

Next.js 서버가 뜰 때, 랜덤 바이트로 만든 hex 문자열을 하나 생성해 전역 심볼로 저장

 

  • crypto.getRandomValues(...)
  • Buffer.from(...).toString('hex')
  • 전역에 Symbol.for('@next/middleware-subrequest-id')로 보관

2) 새 내부 헤더 x-miideware-subrequest-id로 "정상 내부 요청"을 증명

 

  • 요청에 x-middleware-subrequest가 있는데
  • x-middleware-subrequest-id가 전역에 저장된 랜덤 ID와 일치하지 않으면
  • x-middleware-subrequest를 삭제(delete)

즉, 외부 공격자가 증명용 ID 헤더를 맞출 수 없으니 x-middleware-subrequest가 제거되어 미들웨어 스킵 조건이 성립 x


참고 문헌

  • NVD CVE-2025-29927
  • GitHub Security Advisory (vercel/next.js)
  • Vercel Postmortem
  • SK쉴더스 EQST Insight
  • 꼰머의 보안공부 정리
  • GitHub PoC 저장소(동작 개념 참고)
  • Cloudflare WAF 업데이트/권고 버전
  • Next.js 공식 Middleware 문서

 

 

 

반응형

'Web Study' 카테고리의 다른 글

CVE-2022-29078  (0) 2026.02.19
Prototype Pollution  (0) 2026.02.14
XS - Search  (1) 2026.01.07
XXE Injection  (0) 2026.01.04
HTTP request Smuggling  (0) 2026.01.03
'Web Study' 카테고리의 다른 글
  • CVE-2022-29078
  • Prototype Pollution
  • XS - Search
  • XXE Injection
y3onbug5
y3onbug5
y3onbug5 님의 블로그 입니다.
  • y3onbug5
    y3onbug5 님의 블로그
    y3onbug5
  • 전체
    오늘
    어제
    • 분류 전체보기 (167) N
      • Alpacahack (19) N
      • Dreamhack 워게임 (49)
        • Lv.1 (40)
        • Lv.0 (4)
        • LV.2 (3)
        • LV.3 (2)
      • [Dreamhack] Web Beginner (3)
      • [Dreamhack] Web Hacking (17)
        • 웹 기초 지식 (4)
        • Cookie & Session (2)
        • Cross-Site Scripting(XSS) (1)
        • Cross-Site Request Forgery (1)
        • SQL Injection (4)
        • NoSQL Injection (2)
        • Command Injection (1)
        • File Vulnerability (1)
        • Server-Side Request Forgery (1)
      • [Dreamhack] Web Hacking Client-Side (10)
        • XSS Filtering Bypass (2)
        • Content Security Policy (CSP) (2)
        • CSRF,CORS Bypass (2)
        • Client-Side Template Injection (CSTI) (1)
        • CSS Injection (1)
        • Relative Path Overwrite (RPO) (1)
        • DOM Vulnerability (1)
      • [Dreamhack] Web Hacking Server-Side (15)
        • SQL Injection Advanced (4)
        • SQL Injection Advanced - Fingerprinting (2)
        • NoSQL Injection Advanced (3)
        • Command Injection Advanced - Web Servers (3)
        • File Vulnerability Advanced - Web Server (3)
      • [Dreamhack]Black-Box Penetration Testing (15)
        • DreamCommunity Penetration Testing (11)
      • [Dreamhack] LLM (2)
        • [Dreamhack] LLM과 프롬프트 엔지니어링 (2)
      • Web 공부 (4)
      • Web Study (15)
      • JavaScript (17)
        • 기초 (12)
        • 중급 (4)
      • 웹 개발(Flask) (0)
      • [Security First] web 기초교육 (1) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    xss
    LLM
    webstudy
    DreamHack
    webhacking
    CSRF
    hacking
    cve
    web
    JS
    JavaScript
    alpacahack
    드림핵
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
y3onbug5
CVE-2025-29927
상단으로

티스토리툴바