Tu cliente llama: su tienda WooCommerce fue hackeada de nuevo. Lo limpiaste el mes pasado—removiste la puerta trasera, parchaste veintitrés plugins, rotaste credenciales. Pero esta mañana su procesador de pagos marcó actividad sospechosa de tarjetas. Entras por SSH y lo encuentras: un skimmer de tarjetas de crédito escondido dentro de un plugin de análisis que parecía legítimo y se actualizó automáticamente el martes por la noche. Misma historia, diferente plugin. La superficie de ataque no es un bug en el núcleo de WordPress—son treinta y siete plugins de terceros de los que su sitio depende para funcionar. Cada uno es una puerta. La mayoría se parchean lentamente. Algunos nunca lo hacen. La migración a Next.js + Supabase no solo limpia la infección—elimina la capa de plugins completa donde se originan el 90% de los brechas de WordPress.

Este artículo no trata de criticar WordPress. Alimentó una gran parte de la web por una buena razón. Pero la arquitectura que la hizo accesible en 2005 es la misma que la convierte en un imán para ataques automatizados en 2026. Si has sido hackeado—o estás cansado de gastar dinero en plugins de seguridad que son ellos mismos vectores de ataque—este es tu playbook para moverte a algo fundamentalmente más seguro.

Tabla de contenidos

¿WordPress hackeado? Por qué la migración a Next.js + Supabase es tu mejor solución

El problema de seguridad de WordPress es arquitectónico

Debes estar claro en algo: el equipo principal de WordPress hace un trabajo de seguridad sólido. WordPress core, mantenido actualizado, es razonablemente seguro. Pero nadie ejecuta solo WordPress core. El sitio WordPress promedio tiene 20-30 plugins instalados. Cada uno es una dependencia que no escribiste, mantenida por alguien que no conoces, con acceso a tu base de datos, tu sistema de archivos y los datos de tus usuarios.

Aquí está la cosa que siempre se pierde en los artículos de "mejores prácticas de seguridad de WordPress": el problema no es que los propietarios de sitios WordPress sean negligentes. El problema es que la arquitectura de WordPress requiere que instales código PHP ejecutable de terceros directamente en tu servidor para obtener funcionalidad básica. Es equivalente a darle a cada contratista que trabaja en tu casa una copia permanente de tu llave de casa.

La base de datos de vulnerabilidades de WPScan registró más de 7,900 nuevas vulnerabilidades de WordPress en 2024, con plugins representando aproximadamente el 96% de ellas. El reporte de amenazas 2024 de Sucuri encontró que WordPress representó aproximadamente el 95% de todas las infecciones de CMS que limpiaron. Y Patchstack reportó que el 33% de las vulnerabilidades críticas de WordPress en 2024 no tenían parche disponible en el momento de la divulgación.

Estos no son bugs que puedan ser arreglados con mejores prácticas de codificación. Son propiedades emergentes de la arquitectura misma.

Vectores de ataque comunes de WordPress en 2026

Antes de hablar de la solución, vamos a catalogar contra qué estás realmente defendiéndote. He triado personalmente docenas de sitios WordPress comprometidos, y los ataques caen en patrones predecibles.

Inyección SQL a través de plugins

WordPress usa una base de datos MySQL con un esquema bien documentado. Cada plugin que acepta entrada de usuario y toca la base de datos es un posible punto de inyección SQL. La función $wpdb->prepare() existe, pero es opt-in. Los desarrolladores de plugins la olvidan, la usan mal, o la omiten completamente para consultas "simples".

Una vez rastreé una inyección de vuelta a un plugin de formulario de contacto que había sido abandonado por 18 meses pero todavía estaba instalado en más de 200,000 sitios. El atacante estaba usando una inyección basada en UNION para volcar la tabla wp_users, obtener hashes de contraseña de administrador, y crackearlos offline.

-- Lo que una inyección SQL típica de WordPress se ve como en logs
GET /wp-content/plugins/vulnerable-plugin/ajax.php?id=1%20UNION%20SELECT%201,user_login,user_pass,4,5%20FROM%20wp_users--

Inyección de objetos PHP y ejecución remota de código

El uso intensivo de serialize() y unserialize() de WordPress crea oportunidades para inyección de objetos PHP. Cuando un plugin deserializa datos controlados por el usuario (y muchos lo hacen), un atacante puede crear payloads que ejecuten código arbitrario durante el proceso de deserialización.

En 2024, una vulnerabilidad RCE crítica en un popular plugin de backup (instalado en más de 5 millones de sitios) permitía a atacantes no autenticados ejecutar código PHP arbitrario. La solución tardó 11 días en entregarse. Once días donde cada sitio con ese plugin era un pato sentado.

Ataques de cadena de suministro de plugins

Este es el que me asusta más. Los atacantes compran plugins abandonados con grandes bases de instalación, empujan una "actualización de seguridad" que contiene una puerta trasera, y los mecanismos de auto-actualización de WordPress distribuyen el malware a cada sitio que ejecuta ese plugin. Pasó con Display Widgets (300,000 instalaciones) y Social Warfare (70,000 instalaciones), y esos son solo los que fueron detectados.

Ataques de fuerza bruta en wp-login.php

Cada sitio WordPress expone /wp-login.php y /xmlrpc.php por defecto. Las botnets automatizadas golpean constantemente estos endpoints. Wordfence reportó bloquear un promedio de 3 mil millones de solicitudes maliciosas por mes en 2024 en toda su red. Incluso con limitación de velocidad y autenticación de dos factores, estás gastando recursos del servidor procesando estos ataques.

Cross-Site Scripting (XSS) almacenado a través de temas y plugins

XSS almacenado en WordPress es particularmente peligroso porque el dashboard de administrador y el sitio público comparten el mismo contexto de sesión. Un payload XSS inyectado a través de un comentario, un envío de formulario, o una configuración de plugin vulnerable puede escalarse a acceso total de administrador.

Por qué la arquitectura headless elimina categorías completas de ataque

Aquí es donde las cosas se ponen interesantes. Una arquitectura headless no solo reduce tu superficie de ataque—elimina categorías completas de ataques al remover las condiciones que los hacen posibles.

En una configuración WordPress tradicional, el mismo servidor que renderiza tu HTML también:

  • Ejecuta código PHP de 20+ plugins de terceros
  • Maneja autenticación de usuario
  • Se conecta a la base de datos
  • Sirve la interfaz de administración
  • Maneja subidas de archivo
  • Procesa envíos de formulario

Eso son muchas responsabilidades para una sola aplicación. En una configuración headless con Next.js y Supabase, estas responsabilidades se dividen entre servicios aislados:

  • Frontend (Next.js en Vercel/Netlify): HTML/JS estático servido desde un CDN. Sin runtime del lado del servidor expuesto a Internet en la mayoría de los casos.
  • Base de datos + autenticación (Supabase): Postgres administrado con seguridad de nivel de fila, nunca expuesto directamente a usuarios finales.
  • Capa de API: Funciones sin servidor con endpoints explícitos y mínimos.
  • CMS (si es necesario): CMS headless ejecutándose en su propia infraestructura aislada.

No hay PHP en qué inyectar. No hay directorio de plugins con acceso de escritura. No hay sesión compartida entre administración y el sitio público. No hay wp-login.php para que los bots golpeen.

No necesitas un WAF para proteger una superficie de ataque que no existe.

¿WordPress hackeado? Por qué la migración a Next.js + Supabase es tu mejor solución - arquitectura

Next.js + Supabase: Un stack enfocado en seguridad

Vamos a ser específicos sobre por qué esta combinación particular funciona tan bien desde una perspectiva de seguridad.

Next.js: El frontend que no ejecuta código

Cuando construyes un sitio Next.js con generación estática (SSG) o regeneración estática incremental (ISR), lo que se implementa son archivos HTML, CSS y JavaScript en un CDN. No hay un servidor de aplicación procesando solicitudes en tiempo real. No puedes hacer inyección SQL a un CDN.

Para funcionalidad dinámica, las Server Actions y Route Handlers de Next.js se ejecutan como funciones sin servidor. Cada función es:

  • Aislada en su propio contexto de ejecución
  • Sin estado (sin memoria compartida entre solicitudes)
  • De corta duración (inicio en frío, ejecuta, termina)
  • Explícitamente definida (sin auto-descubrimiento de endpoints)
// Route Handler de Next.js -- explícito, tipado, mínimo
import { createClient } from '@/lib/supabase/server'
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'

const ContactSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  message: z.string().min(10).max(5000),
})

export async function POST(request: NextRequest) {
  const body = await request.json()
  const parsed = ContactSchema.safeParse(body)
  
  if (!parsed.success) {
    return NextResponse.json({ error: 'Invalid input' }, { status: 400 })
  }
  
  const supabase = await createClient()
  const { error } = await supabase
    .from('contact_submissions')
    .insert(parsed.data)
  
  if (error) {
    return NextResponse.json({ error: 'Submission failed' }, { status: 500 })
  }
  
  return NextResponse.json({ success: true })
}

Compáralo con un plugin de formulario de contacto de WordPress que tiene que conectarse al sistema de acciones de WordPress, incluir su propio manejador AJAX, manejar su propia verificación de nonce, y construir sus propias consultas SQL. La versión de Next.js tiene menos partes móviles, entrada validada vía Zod, y consultas parametrizadas a través del cliente de Supabase.

Supabase: Postgres con seguridad de nivel de fila

Supabase te da una base de datos PostgreSQL administrada con una característica matadora: Seguridad de Nivel de Fila (RLS). En lugar de confiar en tu código de aplicación para hacer cumplir el control de acceso (el modelo de WordPress), defines políticas de seguridad a nivel de base de datos.

-- Solo usuarios autenticados pueden leer sus propios datos
CREATE POLICY "Users can view own profile"
  ON profiles
  FOR SELECT
  USING (auth.uid() = user_id);

-- Público puede insertar en contact_submissions pero no leer
CREATE POLICY "Anyone can submit contact form"
  ON contact_submissions
  FOR INSERT
  WITH CHECK (true);

CREATE POLICY "Only admins can read submissions"
  ON contact_submissions
  FOR SELECT
  USING (auth.jwt() ->> 'role' = 'admin');

Incluso si un atacante encuentra una manera de hacer consultas arbitrarias de Supabase (que ya es mucho más difícil sin un contexto de ejecución PHP), las políticas RLS evitan que accedan a datos que no deberían ver. Esta es defensa en profundidad que WordPress fundamentalmente no puede ofrecer porque su sistema de permisos se implementa en código PHP, no a nivel de base de datos.

Supabase también maneja autenticación con soporte integrado para email/contraseña, enlaces mágicos, proveedores OAuth, y autenticación multifactor. Sin plugin requerido. Sin código de terceros ejecutándose en tu servidor.

Comparación de superficie de ataque: WordPress vs Headless

Pongamos esto lado a lado.

Vector de ataque WordPress Next.js + Supabase
Inyección SQL Alto riesgo -- plugins construyen consultas sin procesar Casi cero -- consultas parametrizadas vía cliente Supabase, RLS como respaldo
PHP/Ejecución de código remoto Alto riesgo -- plugins ejecutan PHP del lado del servidor No aplicable -- sin runtime PHP
Cadena de suministro de plugins Riesgo crítico -- auto-actualización distribuye malware No aplicable -- sin ecosistema de plugins
Fuerza bruta (login) Siempre expuesto (wp-login.php, xmlrpc.php) Acceso de administración a través de Supabase Auth o dashboard separado, sin endpoint de login público requerido
XSS (Almacenado) Alto riesgo -- contexto compartido admin/público Bajo riesgo -- React escapa salida por defecto, admin y público son aplicaciones separadas
Explotación de subida de archivo Alto riesgo -- archivos PHP subidos pueden ejecutarse Bajo riesgo -- subidas van a almacenamiento de objetos (Supabase Storage/S3), nunca ejecutados como código
Exposición de base de datos Acceso directo MySQL si servidor es comprometido Base de datos detrás de infraestructura de Supabase, políticas RLS como guardia final
DDoS en origen Servidor debe procesar cada solicitud Activos estáticos en CDN, origen raramente alcanzado
Enumeración de ruta conocida wp-admin, wp-content, wp-includes todos escaneables Sin rutas predecibles, sin rutas de administración expuestas

El playbook de migración: WordPress a Next.js + Supabase

Bien, estás convencido (o tu sitio hackeado te convenció). Aquí te mostramos cómo hacerlo realmente. Hemos ejecutado esta migración suficientemente para tener un proceso repetible.

Fase 1: Triage y auditoría de contenido (Semana 1)

Antes de tocar ningún código, necesitas entender qué realmente tienes.

  1. Exporta todo el contenido de WordPress usando WP-CLI o la API REST. No confíes en exportaciones XML—se pierden campos meta y tipos de post personalizados.
  2. Cataloga toda la funcionalidad proporcionada por plugins. Haz una hoja de cálculo: nombre del plugin, qué hace, si realmente lo necesitas, y qué lo reemplaza.
  3. Mapea estructuras de URL para preservación SEO. Cada URL existente necesita una redirección o una ruta coincidente en Next.js.
  4. Identifica características dinámicas—formularios, búsqueda, cuentas de usuario, ecommerce—que necesitan endpoints de API.
# Exporta contenido de WordPress vía API REST
curl -s "https://yoursite.com/wp-json/wp/v2/posts?per_page=100&page=1" | jq '.' > posts_page1.json
curl -s "https://yoursite.com/wp-json/wp/v2/pages?per_page=100" | jq '.' > pages.json
curl -s "https://yoursite.com/wp-json/wp/v2/media?per_page=100" | jq '.' > media.json

Fase 2: Migración de esquema y datos de Supabase (Semana 2)

Diseña tu esquema de base de datos Supabase basado en la auditoría de contenido. No simplemente repliques el esquema de WordPress—está inflado con tablas de metadatos y blobs de datos serializados.

-- Esquema limpio y construido a propósito
CREATE TABLE posts (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  title TEXT NOT NULL,
  slug TEXT UNIQUE NOT NULL,
  content TEXT,
  excerpt TEXT,
  featured_image TEXT,
  status TEXT DEFAULT 'draft' CHECK (status IN ('draft', 'published', 'archived')),
  published_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  author_id UUID REFERENCES auth.users(id)
);

-- Habilita RLS inmediatamente
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Published posts are public"
  ON posts FOR SELECT
  USING (status = 'published');

CREATE POLICY "Authors can manage own posts"
  ON posts FOR ALL
  USING (auth.uid() = author_id);

Escribe un script de migración (Node.js o Python) que transforme exportaciones JSON de WordPress en tu nuevo esquema e insértalas en Supabase.

Fase 3: Construcción de Next.js (Semanas 3-5)

Construye tu frontend de Next.js. Si trabajas con un equipo que conoce el stack, esto va rápido. Si necesitas ayuda, nuestro equipo de desarrollo Next.js ha ejecutado esta migración suficientemente para tener opiniones fuertes sobre los patrones correctos.

Decisiones arquitectónicas clave:

  • Generación estática para páginas de contenido—posts de blog, páginas de inicio, páginas acerca de. Estas se convierten en archivos HTML en un CDN.
  • Componentes de servidor para datos dinámicos—buscar desde Supabase en tiempo de solicitud con caché.
  • Route handlers para envíos de formulario—formularios de contacto, suscripciones a boletines, etc.
  • Middleware para redirecciones—maneja todas tus URLs antiguas de WordPress.
// next.config.ts -- maneja redirecciones de URLs de WordPress
const nextConfig = {
  async redirects() {
    return [
      {
        source: '/category/:slug',
        destination: '/blog/category/:slug',
        permanent: true,
      },
      {
        source: '/:year(\\d{4})/:month(\\d{2})/:slug',
        destination: '/blog/:slug',
        permanent: true,
      },
      // wp-login.php -- envía bots a un 410
      {
        source: '/wp-login.php',
        destination: '/gone',
        permanent: true,
      },
      {
        source: '/wp-admin/:path*',
        destination: '/gone',
        permanent: true,
      },
    ]
  },
}

Fase 4: Testing y validación SEO (Semana 6)

  • Ejecuta Screaming Frog contra el nuevo sitio para verificar que cada URL antigua se resuelva o se redirija.
  • Valida que los datos estructurados (JSON-LD) estén presentes en todas las páginas.
  • Prueba todos los formularios y características dinámicas.
  • Ejecuta comprobaciones de Lighthouse y Core Web Vitals—casi seguramente verás mejoras ya que ahora estás sirviendo desde un CDN.
  • Configura monitoreo con Vercel Analytics o tu herramienta preferida.

Fase 5: Lanzamiento y cambio de DNS (Semana 6-7)

Implementa en Vercel o Netlify, actualiza DNS, y configura monitoreo. Mantén la instancia antigua de WordPress sin conexión pero accesible durante 30 días en caso de que necesites referenciar algo.

Si tu sitio tiene tráfico significativo o funcionalidad de ecommerce, considera una integración de CMS headless para gestión de contenido y habla con nosotros sobre Astro como una alternativa de frontend para sitios ricos en contenido donde el rendimiento de construcción importa.

Refuerzo de seguridad post-migración

Una vez que estés en el nuevo stack, aquí está tu lista de verificación de seguridad:

  1. Habilita RLS en Supabase en cada tabla. Sin excepciones. Si una tabla no tiene políticas, es inaccesible (buen default) o abierta de par en par (malo).
  2. Usa variables de entorno para todos los secretos. Vercel y Netlify manejan bien esto. Nunca commits claves API.
  3. Configura backups de base de datos Supabase. La recuperación en un punto específico está disponible en planes Pro ($25/mes).
  4. Configura encabezados Content Security Policy en tu middleware de Next.js.
  5. Habilita la protección DDoS de Vercel (incluida en todos los planes).
  6. Configura monitoreo de tiempo de actividad—nosotros usamos Better Uptime, pero Checkly y el monitoreo integrado de Vercel también funcionan.
  7. Audita tus políticas RLS de Supabase trimestralmente. Usa el editor SQL de Supabase para probar políticas con diferentes contextos de usuario.
// middleware.ts -- encabezados de seguridad
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  response.headers.set(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
  )
  response.headers.set(
    'Permissions-Policy',
    'camera=(), microphone=(), geolocation=()'
  )
  
  return response
}

Costo real de seguridad WordPress vs migración

Vamos a hablar dinero, porque eso es lo que realmente impulsa las decisiones.

Categoría de costo WordPress (Anual) Next.js + Supabase (Anual)
Hosting $300-1,200 (WP administrado) $0-240 (Vercel Pro)
Plugins de seguridad (Wordfence/Sucuri) $200-500 $0 (no necesarios)
SSL/CDN $0-200 $0 (incluido)
Limpieza de malware (si es hackeado) $500-2,500 por incidente N/A
Tiempo de desarrollador en parches de seguridad $2,000-5,000 $500-1,000
Base de datos (Supabase) Incluida en hosting $0-300 (Tier gratuito a Pro)
Total $3,000-9,400 $500-1,540

Y eso es antes de que factorices el costo del tiempo de inactividad, pérdida de confianza del cliente, y posibles sanciones regulatorias si los datos del cliente se ven comprometidos. Una sola brecha reportable por GDPR puede costar decenas de miles en gastos legales y de cumplimiento.

La migración misma típicamente cuesta entre $10,000-40,000 dependiendo de la complejidad del sitio. Para la mayoría de negocios, eso se paga solo dentro de 1-2 años en gastos de seguridad reducidos—y obtienes un sitio más rápido y mantenible en el proceso.

Preguntas frecuentes

¿Es WordPress realmente tan inseguro, o esto está exagerado? WordPress core se mantiene bien. El problema es que prácticamente nadie ejecuta solo core. El ecosistema de plugins es donde viven el 96% de las vulnerabilidades, y no puedes ejecutar un sitio WordPress útil sin plugins. No es exagerado—Sucuri limpió malware de más de 60,000 sitios WordPress en 2024 solamente. La arquitectura requiere que confíes en código PHP de terceros en tu servidor, y esa confianza es explotada constantemente.

¿No puedo simplemente usar mejores plugins de seguridad en lugar de migrar? Los plugins de seguridad son ellos mismos código PHP ejecutándose en tu servidor con acceso profundo del sistema. Wordfence y Sucuri se mantienen bien, pero son curitas en un problema arquitectónico. También agregan carga del servidor, pueden entrar en conflicto con otros plugins, y han tenido sus propias vulnerabilidades a lo largo de los años. Estás agregando complejidad para resolver un problema de complejidad.

¿Cuánto tiempo toma típicamente una migración de WordPress a Next.js? Para un sitio de negocio estándar (10-50 páginas, blog, formularios de contacto), típicamente completamos migraciones en 5-7 semanas. Sitios de ecommerce con WooCommerce son más complejos y pueden tomar 8-14 semanas dependiendo del tamaño del catálogo de productos y funcionalidad personalizada. Si tienes un sitio más simple, contáctanos y podemos darte un cronograma más específico.

¿Perderé mis rankings de SEO cuando migre de WordPress? No si lo haces correctamente. Los pasos críticos son: preservar todas las estructuras de URL o establecer redirecciones 301 apropiadas, mantener tu marcado de datos estructurados, mantener tu contenido intacto, y enviar sitemaps actualizados a Google Search Console. La mayoría de nuestros clientes de migración ven mejoras de ranking dentro de 2-3 meses porque los puntajes de Core Web Vitals mejoran dramáticamente cuando te mueves a un sitio estático servido desde CDN.

¿Qué hay de edición de contenido? WordPress es fácil para usuarios no técnicos. Esta es una preocupación legítima. Tienes opciones: Supabase con un dashboard de administración personalizado, o un CMS headless como Sanity, Contentful, o Payload CMS que te da una experiencia de edición visual similar a WordPress. Manejamos integraciones de CMS headless regularmente y podemos recomendar el ajuste correcto para las necesidades de tu equipo.

¿Es Supabase lo suficientemente seguro para uso en producción? Supabase se ejecuta en infraestructura AWS con conformidad SOC 2 Tipo II. La base de datos subyacente es PostgreSQL, que tiene un fuerte historial de seguridad. Row Level Security (RLS) hace cumplir el control de acceso a nivel de base de datos, que es realmente más seguro que el sistema de permisos basado en PHP de WordPress. Supabase también ofrece recuperación en un punto específico, conexiones encriptadas, y restricciones de red en planes pagados.

¿Y si mi sitio WordPress ha sido hackeado y necesito ayuda inmediata? Primero, saca el sitio sin conexión inmediatamente para detener daño adicional y fuga de datos. Segundo, preserva evidencia forense (dumps de base de datos, logs de acceso, snapshots del sistema de archivos). Tercero, no solo lo limpies y lo devuelvas—probablemente serás reinfectado dentro de semanas. Usa el incidente como catalizador para migrar. Contáctanos y podemos ayudar con triage inmediato y planificación de migración.

¿Debo migrar todo de una vez, o puedo hacerlo incrementalmente? La migración incremental es posible pero agrega complejidad. Puedes ejecutar Next.js como frontend mientras mantienes WordPress como backend de CMS headless temporalmente, luego eliminar gradualmente WordPress completamente. Sin embargo, esto significa que WordPress aún se está ejecutando y aún necesita mantenimiento de seguridad durante la transición. Para la mayoría de sitios, un cutover limpio es más rápido, más barato, y elimina riesgo de seguridad antes.