Seguridad server actions Next.js 2026: bypass middleware y fixes
En 2026 Next.js publicó 13 avisos sobre bypass de middleware, cache poisoning y SSRF. Esto cambió y cómo proteger hoy las server actions de tu app.
La seguridad frontend en Next.js es la disciplina de proteger server actions, middleware, server components y comportamiento de caché para que una ruta UI no pueda convertirse en una fuga de datos no autenticada o en un vector de denegación de servicio. La superficie de ataque en 2026 es distinta a la de 2023 porque tres de las funciones más populares del framework están ahora en el camino crítico de las decisiones de autorización: middleware, server actions y la caché de los React Server Components.
Solo en 2026, Vercel coordinó una release que parcheó 13 avisos distintos sobre bypass de middleware, server-side request forgery, cross-site scripting y cache poisoning en el App Router. Las versiones con la corrección son Next.js 15.5.16 y 16.2.5 (changelog de Vercel, mayo 2026). Si vuestra aplicación se aprovisionó antes de mayo 2026 y no se ha actualizado, cada sección a continuación os concierne ahora mismo.
Por qué esto es más difícil de lo que parece
Entre Next.js 13 y 16 cambiaron dos cosas que han movido silenciosamente la responsabilidad de la seguridad. Primero, las server actions se convirtieron en la superficie de mutación por defecto, reemplazando el layer de API routes donde vivían los controles de autorización. Segundo, el middleware se convirtió en el layer de autorización por defecto para las aplicaciones del App Router, reemplazando los guards por ruta en páginas protegidas. Ambos cambios son ganancias ergonómicas. Ambos transforman un solo mal uso en un bypass completo.
CVE-2025-29927, divulgada en marzo de 2025, fue el aviso. El layer del middleware confiaba en una cabecera interna (x-middleware-subrequest) sin verificar su origen. Cualquier petición externa que falsificara la cabecera saltaba el middleware por completo, anulando cada control de autorización escrito allí. CVSS 9.1, versiones afectadas hasta la 12.x (aviso de Snyk). Las aplicaciones alojadas en Vercel y Netlify estaban protegidas en el edge. Las self-hosted quedaron expuestas hasta el parche.
La release de mayo 2026 añadió tres avisos más de bypass de middleware, esta vez sobre URLs .rsc y de segment-prefetch en el App Router. Una URL de prefetch construida a medida podía resolver a la misma página sin ser interceptada por la regla de middleware prevista, otorgando de nuevo acceso a contenido protegido (Netlify security update, mayo 2026).
La solución obvia que por sí sola no basta
El reflejo es centralizar la autorización en el middleware. Parece limpio: un archivo, un solo lugar donde leer quién puede hacer qué. El defecto es que el middleware corre a nivel de routing, no a nivel de datos. Todo lo que evita el routing, ya sea por una CVE, un proxy mal configurado, un patrón de ruta no coincidente o una ruta de prefetch estática, también evita vuestra autorización. La guía oficial de Vercel ahora es explícita: el middleware se usa para controles optimistas (redirecciones, detección de locale), y la autorización real vive junto a los datos (guía de autenticación de Next.js).
Qué funciona realmente en 2026
Tratad cada server action como una public API route
Una server action es invocable desde cualquier cliente que conozca el ID de la acción. La defensa CSRF del framework compara las cabeceras Origin y Host y rechaza los mismatches, bloqueando los típicos form posts cross-origin (blog de seguridad de Next.js). Pero no comprueba quién es la persona que llama. Cada action que publicáis necesita tres controles en orden: validación de entrada (Zod o Valibot), autenticación (es una sesión iniciada), autorización (este usuario puede actuar sobre este recurso concreto). Saltad cualquiera de los tres y tenéis una mutación sin autenticar en producción.
Consolidad el acceso a datos en un DAL
El patrón Data Access Layer es la pieza de arquitectura que sobrevive consistentemente a los saltos de versión de Next.js. Cada lectura y cada mutación pasa por un único módulo que recibe la sesión actual y el recurso solicitado como entradas, y devuelve o los datos o una respuesta denegada. Server actions y server components llaman ambos al DAL; ninguno habla directamente con la base de datos. Dos beneficios: la lógica de autorización deja de dispersarse por decenas de archivos de action, y vuestras reglas RLS a nivel de base de datos se convierten en un control de defensa en profundidad en lugar del principal.
Usad la taint API para objetos de alto riesgo
Los métodos experimental_taintObjectReference y experimental_taintUniqueValue de React permiten marcar un objeto de usuario o un token de manera que React rechace serializarlo en el payload de un Client Component. Activado mediante experimental.taint en next.config.js, esto detecta una clase completa de exposiciones accidentales en las que un server component pasa una fila de base de datos que contiene un password hash o una API key a un componente cliente hijo (documentación de React). Advertencia: el taint sigue objetos por referencia, así que un spread o una copia desmarca el resultado. Es una última línea de defensa, no la única.
Nunca capturéis datos sensibles en los closures de server actions
Una server action definida dentro de un server component puede cerrar sobre variables locales. Esas variables se serializan como parte del payload de transporte de la action y quedan visibles para cualquiera que inspeccione la red. La regla que aplicamos: las server actions viven en archivos "use server" separados, y solo capturan identificadores no sensibles a los que el usuario ya tiene acceso, como un slug de URL o un ID público. Cualquier cosa que requiera buscarse en el servidor se busca en el servidor desde la sesión.
Cache poisoning: asumid que vuestro CDN se equivocará
CVE-2025-49826 es el ejemplo más limpio de cómo los layers de caché y de routing divergen. Una respuesta 204 No Content desde una ruta ISR o SSR de Next.js podía ser cacheada por un CDN configurado para cachear respuestas vacías, y una vez cacheada, cada visitante posterior recibía una página en blanco (análisis de ZeroPath de la CVE-2025-49826). La defensa es doble: mantened Next.js parcheado (15.1.8 o posterior corrige esta CVE específica), y configurad vuestro CDN para no cachear nunca respuestas 204 para rutas HTML. Probadlo con un 204 deliberado desde staging y verificad la cabecera de caché en la respuesta.
Lista blanca de orígenes explícita, no confiéis en los defaults
Las server actions aceptan la petición solo cuando Origin coincide con Host, pero las configuraciones de producción detrás de un balanceador de carga o un proxy necesitan que X-Forwarded-Host esté correctamente puesto. Si vuestro reverse proxy lo elimina, el layer de action recae en los defaults y vuestra protección CSRF se vuelve inconsistente. Configurad serverActions.allowedOrigins en next.config.js para cualquier origen externo que aceptéis intencionadamente, incluidos los preview deployments, y auditadlo como parte del checklist de despliegue.
Parchead el mismo día, no el mismo trimestre
La release de mayo 2026 metió 13 fixes en dos bumps de versión. El tiempo medio entre la divulgación y los intentos de explotación de CVEs de Next.js se ha reducido cada año desde 2024. CVE-2025-29927 tuvo proof-of-concept público a las 24 horas de la divulgación (Datadog Security Labs). Suscribíos a los avisos de seguridad de vercel/next.js en GitHub, automatizad los PRs de dependencias mediante Dependabot o Renovate, y publicad los parches de seguridad el mismo día que aterrizan.
Cómo se ve esto en la práctica
En un proyecto SaaS reciente ejecutamos la auditoría en una aplicación App Router de 28 rutas aprovisionada a finales de 2024. La aplicación tenía autorización solo en middleware, server actions inline en componentes de página y sin DAL. Hallazgos: 12 server actions que no re-comprobaban la sesión, 4 actions que capturaban IDs de usuario desde closures en vez de desde la sesión, 1 página que pasaba una fila completa de Supabase con una columna protegida por service-role a un componente cliente, y un Next.js desactualizado (14.1) expuesto a la CVE de bypass de middleware.
La secuencia de fix tomó 9 días laborables: bump de Next.js y React, extracción de cada server action a archivos app/actions/*.ts, introducción de un DAL con un único guard requireSession, sustitución de los IDs capturados en closures por IDs derivados de la sesión, activación de taint sobre objetos de usuario y tenant, y un paso de CI que falla el build si un archivo "use server" no importa el DAL. Tras la auditoría, la aplicación pasó un pentest externo con cero hallazgos de autorización.
Studio
Empieza un proyecto.
Un partner único para empresas, sector público, startups y SaaS. Producción más rápida, tecnología moderna, costes reducidos. Un equipo, una factura.