
Асинхронный RCE-сканер для CVE-2025-55182 / CVE-2025-66478 — prototype pollution → выполнение кода через React Server Actions.
Асинхронное обнаружение через канарейку (canary) с приоритетом версии — без слепого подбора
[!WARNING] Только для авторизованных исследований безопасности и пентеста. Сканирование систем без явного письменного разрешения противозаконно. Автор не несёт ответственности за неправомерное использование этого инструмента.
React Server Actions передают данные действия как multipart form data напрямую в серверный контекст выполнения. Из-за недостаточной санитизации prototype pollution в затронутых версиях react-server-dom-webpack атакующий может:
Object.prototype_response._prefix во внутреннем объекте ответаprocess.mainModule.require('child_process').execSync(cmd)
Это даёт неаутентифицированное удалённое выполнение кода (RCE) на любом публично доступном Next.js-приложении, использующем React Server Actions с затронутой версией React.
CVE-2025-55182 — Широкий охват: затрагивает пакеты React 19 (react-server-dom-webpack, react-server-dom-parcel, react-server-dom-turbopack)
CVE-2025-66478 — Строгий охват: путь эксплуатации, специфичный для Next.js, через Server Action endpoint /
| Компонент | Уязвимые | Исправленные |
|---|---|---|
React react-server-dom-* | 19.0.0, 19.1.0, 19.1.1, 19.2.0 | 19.0.1, 19.1.2, 19.2.1+ |
| Next.js 16.x | 16.0.0 – 16.0.6 | 16.0.7+ |
| Next.js 15.x | 15.0.0-15.0.4, 15.1.0-15.1.8, 15.2.0-15.2.5, 15.3.0-15.3.5, 15.4.0-15.4.7, 15.5.0-15.5.6 | 15.0.5+, 15.1.9+, 15.2.6+, 15.3.6+, 15.4.8+, 15.5.7+ |
| Next.js 14.x | только canary-сборки 14.3.0-canary.77+ | Все стабильные 14.x — НЕ ЗАТРОНУТЫ |
| Next.js 13.x | - | НЕ ЗАТРОНУТЫ |
Этот сканер использует проверку канарейки по выводу (output-based canary verification) — самый надёжный метод подтверждения реального выполнения кода с нулевым количеством ложных срабатываний:
1. POST / с заголовком Next-Action + multipart-пейлоад prototype pollution
2. Пейлоад выполняет: echo <random_canary>
3. Уязвимый сервер выбрасывает NEXT_REDIRECT с base64(canary) в URL
4. Заголовок ответа: X-Action-Redirect: /login?a=<base64(canary)>
5. Сканер декодирует base64 → совпадение с канарейкой → RCE подтверждён ✓
allow_redirects=False критически важно — подтверждение находится в заголовке, а не в месте перенаправления.
git clone https://github.com/InferiorAK/React2Shell
cd React2Shell
pip install -r requirements.txt
# Требуется только при использовании режима --browser для улучшенного определения версии:
playwright install chromium
playwright install-deps chromium
Требования: Python 3.10+
# Одиночная цель
python3 CVE-2025-55182_scanner.py -u https://target.com
# Сканирование списка URL
python3 CVE-2025-55182_scanner.py -f urls.txt
# Тихий режим — вывод только результатов RCE / Vulnerable
python3 CVE-2025-55182_scanner.py -f urls.txt -q
# Режим браузера — headless Chromium для точного определения версии
python3 CVE-2025-55182_scanner.py -f urls.txt -b
# Полный набор опций — рекомендуется для масштабного сканирования
python3 CVE-2025-55182_scanner.py -f urls.txt -b -q -c 3 -t 20
| Флаг | Длинная форма | По умолчанию | Описание |
|---|---|---|---|
-u | --url | - | URL одиночной цели |
-f | --file | - | Файл с одним URL на строку |
-o | --output | outputs/vuln.txt | Выходной файл для уязвимых целей |
-U | --unknown-output | outputs/unknown.txt | Выходной файл для целей с неизвестной версией |
-c | --concurrency | 5 | Параллельные HTTP-соединения |
-t | --timeout | 15 | Таймаут на запрос (секунды) |
-q | --quiet | выкл | Выводить только строки RCE / VULNERABLE |
-b | --browser | выкл | Запасной вариант определения версии через Playwright headless Chromium |
Каждой сканируемой цели присваивается один из следующих вердиктов:

| Вердикт | Цвет | Значение |
|---|---|---|
RCE | 🔴 Красный | Канарейка подтверждена в X-Action-Redirect — доказанное удалённое выполнение кода |
VULNERABLE | 🟠 Оранжевый | Версия попадает в уязвимый диапазон; RCE-пейлоад не вернул эхо (WAF / пропатченная конфигурация / неверный endpoint) |
Unknown | 🟡 Жёлтый | Next.js подтверждён, но версию определить не удалось — RCE всё равно опробован; сохранено в outputs/unknown.txt для повтора в режиме браузера |
Not Vulnerable | 🟢 Зелёный | Версия подтверждена как исправленная, либо RCE явно вернул безопасный результат |
Skipped | ⚪ Белый | Подтверждённая пропатченная версия или сайт не на Next.js — PoC не выполнялся |
Error | ⚪ Белый | Хост недоступен или соединение не удалось |
Выходные файлы (сохраняются в папку outputs/, создаётся автоматически):
outputs/vuln.txt — результаты RCE и VULNERABLE (дописываются при каждом запуске)outputs/unknown.txt — цели с версией Unknown; повторите их с флагом -b для точного определения версииПочему версия отображается как
unknownна 90%+ сайтов?
Современный Next.js 13+, использующий архитектуру App Router, никогда не встраивает версию фреймворка в статический HTML. Версия существует только в window.next.version после выполнения JavaScript в реальном браузерном контексте.
Без --browser:
__NEXT_DATA__, инлайн-скрипты и хэшированные файлы чанковunknown — фильтрация по версии обходитсяС --browser (-b):
window.next.version напрямую из живого DOM# Рекомендуется с режимом браузера — снизьте конкурентность (страницы браузера требовательны к ресурсам)
python3 CVE-2025-55182_scanner.py -f urls.txt -b -c 3
Сканер выполняет до 7 этапов, останавливаясь сразу после нахождения версии:
Stage 1 │ HTTP-заголовки ответа
│ X-Powered-By: Next.js X.Y.Z
│ x-nextjs-*, x-next-version
Stage 2 │ Инлайн-блоки <script> (поиск по каждому блоку)
│ window.next = { version: "X.Y.Z", ... }
│ version:"X.Y.Z", router: ... ← паттерн смежного ключа в минифицированном бандле
│ "nextVersion":"X.Y.Z"
│ Next.js vX.Y.Z ← обычный текст в meta / HTML-комментариях
│ __NEXT_VERSION__ = "X.Y.Z"
Stage 3 │ JSON-блок __NEXT_DATA__
│ Только Pages Router — "version":"X.Y.Z" безопасен в этом контексте
Stage 4 │ Хэшированные URL чанков (извлечены из <script src>)
│ /_next/static/chunks/*, /_next/static/app/*, /_next/static/runtime/*
│ Загружает до 12 реальных файлов бандлов и сканирует их на строки версий
Stage 5 │ Запасные чанки с фиксированными именами
│ main.js, framework.js, webpack.js, _app.js, pages/_app.js
Stage 6 │ Endpoint /package.json
│ Dev-режим / некорректно настроенные серверы отдают его напрямую
Stage 7 │ Playwright Headless Browser [только --browser / -b]
│ Вычисляет window.next.version после полного выполнения JS
│ Срабатывает только когда этапы 1–6 вернули "unknown"
Этот инструмент опубликован исключительно в образовательных целях и для авторизованных исследований безопасности.
Автор, InferiorAK, не несёт ответственности за любой ущерб, причинённый в результате неправомерного использования.
Всегда получайте письменное разрешение перед тестированием любой системы, которая вам не принадлежит.
Сделано InferiorAK
Мои ссылки