关联漏洞
介绍
# 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 (многопоточная активная проверка на тестовых хостах).
---
## Суть уязвимости

- **Первопричина.** В 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付费,感谢您的支持。