POC详情: 5ccd8ef25223b9d8ae48dae97280f5ff641f5c4d

来源
关联漏洞
标题: Next.js 安全漏洞 (CVE-2025-29927)
描述:Next.js是Vercel开源的一个 React 框架。 Next.js 14.2.25之前版本和15.2.3之前版本存在安全漏洞,该漏洞源于如果授权检查发生在中间件中,可能绕过授权检查。
介绍
# CVE-2025-29927

## Введение

В данном документе представлено исследование уязвимости **CVE-2025-29927**, затрагивающей механизм **Middleware** во фреймворке **Next.js**.  
Next.js — популярный open-source фреймворк от Vercel для разработки приложений на базе React. Он поддерживает серверный рендеринг, статическую генерацию и гибкую систему промежуточного ПО (middleware), применяемую для маршрутизации, перенаправлений, заголовков безопасности и проверки прав доступа.

В марте 2025 года была выявлена критическая уязвимость **CVE-2025-29927**, связанная с обработкой служебного заголовка внутренних подзапросов.  
Суть проблемы — возможность **обойти авторизационные проверки** в приложениях, где контроль доступа реализован именно в middleware, путём подстановки особого значения в HTTP-заголовок `x-middleware-subrequest`. Если безопасность завязана только на middleware, злоумышленник может получить доступ к закрытым маршрутам или данным.

**Затронутые версии Next.js** и исправления (по публичным источникам и официальным материалам):

- 11.1.4 ≤ версия < 12.3.5  
- 13.0.0 ≤ версия < 13.5.9  
- 14.0.0 ≤ версия < 14.2.25  
- 15.0.0 ≤ версия < 15.2.3  

Исправления доступны в релизах **12.3.5 / 13.5.9 / 14.2.25 / 15.2.3**.

Next.js широко применяется в продакшне; уязвимость, задевающая слой middleware (часто используемый для аутентификации/авторизации и политики безопасности), несёт высокий практический риск.

---

## Цель отчёта

Пошагово разобрать уязвимость и оформить полный цикл исследования:

**Сбор и структурирование материалов.**  
Систематизировать публичные источники по CVE-2025-29927; изложить суть дефекта, условия срабатывания и подтверждённые версии/патчи.

**Определение CPE и условий конфигурации.**  
Привести список CPE/версий и описать конфигурации, при которых уязвимость воспроизводится (например, self-hosted деплой и авторизация на уровне middleware).

**Безопасная демонстрация.**  
Подготовить воспроизводимое демо на тестовой среде (без деструктивных действий), подтверждающее факт обхода middleware в уязвимых версиях.

**Методики массовой проверки.**  
Описать и реализовать три безопасных подхода:
- nuclei (активный режим с минимизацией влияния),
- nuclei (пассивный режим по версиям/косвенным признакам),
- собственный скрипт на Python/Go (многопоточная активная проверка на тестовых хостах).

---

## Суть уязвимости

![middleware](/img/midleware.png)

- **Первопричина.** В Next.js служебный заголовок `x-middleware-subrequest` используется для отслеживания внутренних подзапросов и предотвращения рекурсии в middleware. В уязвимых ветках внешние клиенты могут подставить этот заголовок с «ожидаемым» значением — и рантайм **пропускает выполнение middleware**, передавая запрос напрямую обработчику маршрута.

- **Роль заголовка.**  Сам заголовок `x-middleware-subrequest` изначально задумывался как внутренний индикатор того, что текущий HTTP-запрос запущен самим фреймворком как промежуточный подзапрос, а не пришёл напрямую от пользователя.  
  Он нужен для корректной работы внутренних механизмов Next.js: помимо маршрутизации, этот флаг помогает избежать бесконечной рекурсии, «отмечая» каждый вызванный промежуточный слой.  
  Но именно эта логика породила непреднамеренную дыру в защите: клиент, самостоятельно добавивший такой заголовок, может заставить систему трактовать свой запрос как внутренний и тем самым миновать авторизационные проверки.

- **Эволюция логики.**  
  - В более ранних версиях заголовок интерпретируется как список значений, разделённых двоеточиями, и механизм сопоставляет его с именем/путём активного middleware.  
  - В более новых ветках добавлена защита от бесконечной рекурсии в виде счётчика глубины; при достижении порога (по умолчанию 5) middleware также пропускается. Этот механизм можно обмануть, если заголовок сформирован «как будто» цепочка подзапросов уже исчерпала лимит.

---

## Импакт

- **Конфиденциальность и целостность.** Неавторизованный доступ к защищённым страницам или API при реализации контроля доступа только на уровне middleware; потенциальная модификация данных через защищённые эндпоинты.  
- **Доступность.** Побочные эффекты наподобие **cache poisoning** могут приводить к некорректному кешированию и деградации доступности в ряде конфигураций.

---

## CPE и условия конфигурации

### Официальные CPE (CPE 2.3)

Актуальные записи NVD указывают на продукт **Vercel Next.js** с целевым ПО *node.js*. Для уязвимых веток применяются следующие конфигурации (диапазоны версий заданы на уровне CPE-конфигураций в NVD):

| CPE URI | Уязвимый диапазон версий |
|---|---|
| `cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:*` | 11.1.4 ≤ v < 12.3.5 |
| `cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:*` | 13.0.0 ≤ v < 13.5.9 |
| `cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:*` | 14.0.0 ≤ v < 14.2.25 |
| `cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:*` | 15.0.0 ≤ v < 15.2.3 |

> Примечание: в описании CVE также указывается, что в целом «начиная с 11.1.4 и до 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3» уязвимость воспроизводится при выполнении условий ниже.

### Условия актуальности в продакшн-среде

- Контроль доступа (аутентификация/авторизация) реализован **в middleware** и не дублируется в обработчиках/бэкенде.  
- Деплой **self-hosted** (например, `next start`, сборка с `output: 'standalone'`) или любая среда, где middleware исполняется на входящих запросах без периметровой фильтрации служебных заголовков.  
- Отсутствуют внешние средства, отбрасывающие пользовательские запросы с `x-middleware-subrequest` (например, правила WAF).

---

## Внутренний механизм `x-middleware-subrequest`

Чтобы исключить бесконечную рекурсию промежуточного кода, рантайм формирует и читает служебный заголовок:

1. Значение заголовка интерпретируется как строка с элементами, разделёнными двоеточием `:` — получается массив «подзапросов».  
2. Далее рантайм проверяет:  
   - встречается ли имя/путь текущего middleware в этом массиве (в старых ветках это приводило к немедленному пропуску через `NextResponse.next()`),  
   - либо достигнута ли предельная глубина рекурсии (в новых ветках применяется лимит, по умолчанию **5**), и тогда middleware тоже пропускается.  
3. Для защиты от подделки в патчах добавлен отдельный **идентификатор подзапроса** (`x-middleware-subrequest-id`), связанный с текущей сессией процесса; если он не совпадает, входящий `x-middleware-subrequest` очищается на серверной стороне.

---

## Метод эксплуатации

Злоумышленник посылает HTTP-запрос в целевое Next.js-приложение, добавляя в него служебный заголовок `x-middleware-subrequest`.  
В значении указывается путь до файла middleware — например `pages/_middleware`, `middleware` или `src/middleware`.  
Нужное значение зависит от используемой версии Next.js и от структуры проекта.

Когда такой запрос достигает приложения, внутренняя логика фреймворка воспринимает его как **внутренний подзапрос** и предполагает, что промежуточный слой уже был выполнен.  
В результате проверки аутентификации и авторизации, которые обычно происходят в middleware, фактически пропускаются.

---

## PoC / Exploit

> **Важно:** данный материал приведён исключительно для проверки патча и моделирования риска в закрытой тестовой среде.  
> Любые проверки в продуктивной инфраструктуре возможны только с разрешения владельца ресурсов.

### Общий принцип

Next.js использует служебный заголовок `x-middleware-subrequest`, чтобы отмечать внутренние подзапросы и предотвращать рекурсивный запуск middleware.  
При обработке запроса значение заголовка разбивается по символу `:` и сравнивается с именем текущего middleware.  
В новых версиях добавлен лимит глубины (`MAX_RECURSION_DEPTH`, обычно **5**).  
Если условие (совпадение имени или достижение лимита) выполняется, Next.js **пропускает middleware** и передаёт запрос дальше.  
Атакующий может сформировать корректное значение заголовка, имитируя внутренний подзапрос.

### Эксплуатация по версиям

#### 1️⃣ Версии до **12.2**: Pages Router и `_middleware.*`
- Файлы middleware назывались **`_middleware.js/ts`** и располагались в каталоге **`pages/`**.  
- Значение заголовка должно совпадать с путём к файлу, например:
  `x-middleware-subrequest: pages/_middleware`

#### 2️⃣ Версии **12.2 – 13.0.0**: корневой `middleware.*`
- С версии 12.2 подчёркивание в имени убрано: файл стал **`middleware.js/ts`**.  
- Он может находиться в корне проекта или в корне каталога `/src`.  
- Для обхода middleware используют заголовок: `x-middleware-subrequest: middleware` или `x-middleware-subrequest: src/middleware`

#### 3️⃣ Версии **13.x и новее**: лимит глубины рекурсии
- Добавлена проверка глубины: значение заголовка разбивается по `:`, и если количество повторов имени middleware ≥ **5**,  
Next.js считает условие рекурсии достигнутым и пропускает middleware через `NextResponse.next()`.  
- Для атаки заголовок оформляют так: `x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware` или `x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware`

#### Особенности в Next.js 15.x
В релизах 15.x разработчики переработали логику, чтобы предотвратить бесконечные рекурсивные вызовы.  
Когда в пути срабатывает middleware (например, `/api/*`), Next.js получает другой URL, который тоже инициирует то же middleware.  
Фреймворк считает количество срабатываний через заголовок `x-middleware-subrequest`.  
Если число вызовов достигает установленного порога (`MAX_RECURSION_DEPTH`, по умолчанию **5**), дальнейшие вызовы middleware блокируются.  
Злоумышленник может воспользоваться этим поведением, заранее указав в заголовке значение с нужным количеством повторов и тем самым искусственно достичь лимита глубины — в результате middleware будет полностью пропущен.

### Пример запроса
> *для старых веток значение заголовка выбирается согласно приведённым выше вариантам*
```bash
GET /admin/dashboard HTTP/1.1
Host: <TEST-HOST>
User-Agent: <YOUR-LAB-CLIENT>
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
```

### Почему это работает

`x-middleware-subrequest` задумывался как внутренний механизм защиты от бесконечной рекурсии.  
Но в уязвимых версиях отсутствовала фильтрация внешних запросов: клиент мог подделать заголовок,  
выполнить условие пропуска (совпадение имени или достижение лимита глубины)  
и напрямую обратиться к обработчику защищённого маршрута.

---

文件快照

[4.0K] /data/pocs/5ccd8ef25223b9d8ae48dae97280f5ff641f5c4d ├── [4.0K] img │   └── [1.7M] midleware.png └── [ 16K] README.md 1 directory, 2 files
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。