Seguridad en WordPress: lo que buscan 1.000 ataques reales
Cuando se habla de seguridad en WordPress, casi siempre se habla de contraseñas, de “ocultar” wp-admin o de instalar otro plugin de seguridad. Quise comprobar si eso coincide con lo que de verdad llega a un sitio real, así que analicé los registros de un sitio corporativo en WordPress, en producción, que administro.
Este artículo es lo que encontré. Los números son míos, de dos exportaciones reales y anonimizadas. Los informes externos aparecen solo como contexto y están citados al final.
Lo esencial en tres hallazgos
- Casi nadie va por la contraseña. Solo 3 de 1.000 eventos tocaron
wp-login.php. En cambio, 413 (41,3 %) buscaban archivos sensibles:.env,.git, llaves SSH,.htpasswdy copias de seguridad. - Pocos hacen casi todo el ruido. 9 IPs de 172 (5 %) generaron el 49,3 % de los eventos. Y 73 IPs (42,4 %) aparecieron una sola vez.
- La nube es la plataforma de ataque. El 30,8 % de las IPs bloqueadas pertenece a rangos publicados de Google Cloud, y generó el 34,3 % de los eventos. Bloquear “países sospechosos” no sirve de mucho cuando el ataque sale de un centro de datos común.
De dónde salen los datos
Trabajé con dos exportaciones del mismo sitio. Cada una trae solo las últimas 1.000 filas de su registro, no el historial completo, así que cubren ventanas de tiempo muy distintas y no se pueden comparar en volumen.
Tabla 1: Fuentes de datos y ventana de análisis
| Fuente | Filas | Ventana | IPs únicas |
|---|---|---|---|
| Eventos del firewall (WAF) | 1.000 | 9,3 días (4 al 13 de octubre de 2026) | 172 |
| Access log del servidor | 1.000 | 4,3 horas (13 de octubre de 2026) | 144 |
Anonimicé todo: no publico el dominio, ni IPs completas, ni más datos del sitio. Los eventos del firewall suman 8.587 “coincidencias”, que interpreto como el número de peticiones o reglas agregadas en cada evento (promedio de 8,59 por evento, máximo 178); el export no lo documenta, es una interpretación. Todos los eventos del firewall figuran como bloqueados, así que el archivo solo contiene bloqueos, no tráfico permitido. Más límites al final, en la sección de limitaciones.
El firewall es el de Monarx, que agrupa sus reglas por tipo. Cada tipo reúne varias reglas, y el export solo indica el tipo de cada evento, no la regla exacta. En la tabla pongo, para cada tipo, una regla de ejemplo tomada de la descripción de Monarx:
Tabla 2: Eventos del firewall por tipo de regla
| Tipo de regla | Eventos | Ejemplo de regla (descripción de Monarx) |
|---|---|---|
| Endurecimiento | 462 | Sensitive File Exposure: impide acceder a archivos de entorno y otros archivos sensibles con credenciales de base de datos y llaves de cifrado |
| Explotación | 184 | Block Plugin Droppers and Planted Shells: bloquea malware en rutas de plugins, droppers PHP y shells plantadas dentro de plugins reales |
| Parche | 166 | Next.js Flight Protocol RCE: parche virtual contra una ejecución remota de código sin autenticación en Next.js |
| WAF | 106 | Path Traversal: peticiones que intentan salir de la carpeta permitida con rutas relativas |
| IP | 82 | Malicious sources: IPs asociadas a actividad maliciosa conocida |
Hay un sexto tipo, Fuerza bruta (Scan Lockout: bloquea temporalmente a una fuente que acumula demasiados “no encontrado” o bloqueos). En los 1.000 eventos no apareció ni una vez.
Fíjate en el ejemplo de “Parche”: es una vulnerabilidad de Next.js, no de WordPress. El firewall se protege contra exploits de cualquier stack porque los escáneres los lanzan contra cualquier sitio, sin mirar qué tecnología usa.
1. Casi nadie va por la contraseña
Esta fue la sorpresa más grande. Clasifiqué los eventos por lo que pedían:
{
"type": "bar-horizontal",
"title": "QUÉ BUSCABAN EN EL FIREWALL (1.000 EVENTOS)",
"subtitle": "Eventos por categoría de objetivo, ventana de 9,3 días",
"unit": "eventos",
"max": 450,
"categories": ["Archivos sensibles (.env, .git, backups)", "Raíz / index.php", "Webshells / PHP malicioso", "Exploits de stack que no es WP", "Traversal / LFI", "REST API", "Otros CMS", "Login (wp-login)"],
"series": [
{
"name": "Eventos",
"data": [413, 198, 116, 83, 59, 52, 36, 3]
}
],
"colors": ["#fc4269"]
}
Los 413 eventos de archivos sensibles (el 41,3 % de los eventos, y el 78,8 % de las coincidencias) pedían rutas como /.env (35 eventos), /.git/config (32), /.git/HEAD (9), /.htpasswd (8) o /.ssh/id_rsa (7). Fuerza bruta contra el login: 3 eventos, el 0,3 %.
Qué significa: al atacante automatizado no le interesa adivinar tu clave si una sola petición puede devolverle las credenciales de la base de datos completas. Un .env expuesto vale más que mil intentos de login.
Defensa concreta:
- Nunca dejes archivos de configuración, credenciales, backups ni repositorios dentro de la carpeta pública del servidor.
- Bloquea a nivel de servidor cualquier archivo que empiece por punto. En nginx, por ejemplo:
location ~ /\.(?!well-known) { deny all; }. - Revisa que
/.git/configy/.envdevuelvan 403 o 404 desde fuera.
2. Pocos hacen casi todo el ruido
| Segmento de IPs | IPs | % de eventos | % de coincidencias |
|---|---|---|---|
| Top 1 % | 2 | 16,0 | 38,2 |
| Top 5 % | 9 | 49,3 | 57,0 |
| Top 10 % | 17 | 63,0 | 71,7 |
Dos IPs concentran el 38,2 % de las coincidencias. Al otro extremo, la mediana es de 2 eventos por IP, 73 IPs aparecieron una sola vez y solo 21 IPs reaparecieron en más de un día (máximo, 6 días distintos).
Qué significa: hay un puñado de emisores muy ruidosos y una larga cola de visitantes de un solo disparo. Bloquear IP por IP rinde poco: la próxima ráfaga vendrá de otra dirección.
Defensa concreta: filtra por patrón de petición (reglas de firewall, límites de frecuencia), no por lista de IPs.
3. La nube como plataforma de ataque
Comparé las IPs con los rangos publicados por los proveedores de nube. Google Cloud aportó 53 IPs (30,8 % de las IPs) y el 34,3 % de los eventos. Todo el tráfico de traversal/LFI salió de ahí, y también el 72,3 % de los exploits de stack que no es WordPress.
Tabla 4: IPs y eventos por proveedor de nube
| Proveedor | IPs | % de IPs | % de eventos |
|---|---|---|---|
| Sin rango publicado (residencial, hosting u otro) | 99 | 57,6 | 61,6 |
| Google Cloud | 53 | 30,8 | 34,3 |
| DigitalOcean | 10 | 5,8 | 2,6 |
| AWS | 5 | 2,9 | 0,7 |
| Oracle Cloud | 4 | 2,3 | 0,7 |
| Cloudflare | 1 | 0,6 | 0,1 |
Hay un patrón que me llamó la atención: 8 IPs distintas de Google Cloud registraron casi las mismas coincidencias (unas 214 cada una), en ráfagas de unos 5 minutos, cada una en un día distinto, con el mismo patrón (.env, .git y la raíz). Esto es una inferencia: parece el mismo script lanzado desde máquinas virtuales que rotan, pero con estos datos no puedo atribuirlo a nadie.
Ojo con la lectura: que una IP pertenezca a un rango cloud no significa que Google sea el atacante; esos rangos incluyen máquinas alquiladas por cualquiera. Y el 57,6 % restante no tiene rango publicado: puede ser residencial o hosting no cubierto.
Defensa concreta: no bloquees “toda la nube” a ciegas (también salen de ahí servicios legítimos). Bloquea por comportamiento.
4. Escáneres que buscan vulnerabilidades concretas
Muchas peticiones tienen la forma de una vulnerabilidad conocida. Estas firmas son inferidas por el analista, no declaradas en el log (ninguna ruta contenía un CVE literal):
Tabla 5: Firmas de vulnerabilidades inferidas
| Firma | Eventos |
|---|---|
Archivo .env expuesto | 217 |
REST batch/v1 | 51 |
Repositorio .git expuesto | 46 |
LFI /proc/self/environ | 32 |
Lectura de archivos vía @fs (familia Vite, inferido) | 28 |
| PHP-CGI (CVE-2024-4577, inferido) | 9 |
PHPUnit eval-stdin (CVE-2017-9841, inferido) | 7 |
Dos de esas firmas las pude verificar en la base de vulnerabilidades del NIST. CVE-2017-9841 afecta a versiones antiguas de PHPUnit: su archivo eval-stdin.php permite ejecutar código PHP enviado por POST, sobre todo si la carpeta /vendor es pública. CVE-2024-4577 afecta a PHP-CGI en Windows con Apache en ciertas versiones de PHP y permite ejecutar código; ambas tienen puntaje CVSS 3.1 de 9,8 (crítico). Que mi sitio reciba estas peticiones no significa que sea vulnerable: son sondas que se lanzan a ciegas contra todo.
También vi nombres de supuestos plugins como pwnd, fix o shell, y archivos como up.php o mah.php. No son plugins reales: son rutas de puertas traseras que los atacantes esperan encontrar ya instaladas. En total, 116 eventos de este tipo vinieron de solo 14 IPs.
Un detalle curioso del access log: un cliente con el User-Agent cve-2026-63030/1.0 hizo un POST a /?rest_route=/batch/v1 y recibió un 403. No investigué más allá de lo que muestran los datos.
Defensa concreta: mantén plugins y temas actualizados, elimina los que no uses y apóyate en parcheo virtual como capa extra mientras llega la actualización.
5. Bots que se disfrazan
Seis peticiones a rutas de ataque (por ejemplo /proc/self/environ) llevaban un User-Agent de crawler como CCBot o Meta-ExternalAgent, o “bot” genérico; 5 de las 6 salieron de IPs de Google Cloud. Es probable suplantación (inferencia, no verificada).
Defensa concreta: nunca des acceso o excepciones solo por el User-Agent. Es texto que cualquiera escribe. Si quieres verificar a Googlebot, compáralo con los rangos IP publicados: en mi muestra, las 33 peticiones de Googlebot salieron de rangos de Google.
6. El subdominio de correo también recibe ataques
De los 1.000 eventos, 693 apuntaban al dominio raíz, 238 (23,8 %) al subdominio de correo y 69 a www. Casi un cuarto del ruido no iba al sitio principal.
Defensa concreta: aplica el mismo endurecimiento y las mismas reglas a todos los subdominios, no solo al que ve el público.
7. El tráfico de IA ya supera a los buscadores (en esta ventana)
En el access log, el 8,1 % de las peticiones vino de crawlers de IA y el 5,7 % de buscadores. ClaudeBot fue el más activo (42 peticiones), seguido de Bytespider (17).
Esto es una ventana de solo 4,3 horas, y la clasificación se basa en el User-Agent, que es falsificable. Lo cuento como dato curioso, no como tendencia. Tiene una implicación práctica: decide conscientemente qué crawlers quieres permitir en tu robots.txt, en lugar de dejarlo por defecto.
8. El firewall frena casi todo, pero no todo
En el registro de accesos, el 79,8 % de las peticiones de escáneres terminó en error 4xx: el firewall y el propio WordPress las rechazaron.
Pero hay un detalle que vale más que ese porcentaje. Dos peticiones POST a wp-json/batch/v1, con un User-Agent genérico (Mozilla/5.0), recibieron un 207 Multi-Status. Un 207 no es un error: significa que WordPress procesó la petición por lotes y devolvió un resultado por cada subpetición. Lo más probable es que esas subpeticiones fallaran por falta de autenticación, pero el registro no lo muestra. Lo que sí muestra es que esas dos llegaron hasta la aplicación sin que el firewall las detuviera.
Dos matices más. El bloqueo del firewall es por regla, no un baneo permanente de la IP: una IP bloqueada días antes puede recibir un 200 después. Y la ventana del registro de accesos es corta (4,3 horas). La conclusión práctica: el firewall es una capa, no una garantía. La defensa de fondo sigue siendo tener todo actualizado y no dejar nada sensible al alcance.
Lo que dicen los informes
El informe de Patchstack, State of WordPress Security 2026, que cubre datos de 2025, reporta:
- 11.334 vulnerabilidades nuevas en el ecosistema, un 42 % más que en 2024.
- El 91 % estaba en plugins y el 9 % en temas.
- Solo 6 fueron del núcleo de WordPress, de baja prioridad.
- El 46 % no tenía parche del desarrollador al hacerse pública.
- Una mediana ponderada de 5 horas hasta el primer intento de explotación (en las vulnerabilidades muy explotadas).
Cómo se compara con mis datos: coincide en lo esencial. El riesgo está en el código de terceros y en la velocidad, no en el login. Mi muestra es pequeña y de un solo sitio, así que no la uso para confirmar estadísticas de todo el ecosistema.
Checklist práctico, ordenado por impacto
- Saca los archivos sensibles y los backups del directorio público.
.env,.git,.htpasswd, volcados.sql, copias.bak. - Bloquea archivos ocultos a nivel de servidor (con excepción de
.well-known). - Actualiza plugins y temas con frecuencia y activa actualizaciones automáticas para los de seguridad.
- Elimina plugins y temas que no uses, incluso desactivados.
- Usa un firewall con reglas por patrón y parcheo virtual; no dependas de listas de IPs.
- Impide ejecutar PHP en
wp-content/uploads. - No publiques
/vendorni dependencias de desarrollo en producción (por ejemplo PHPUnit). - Protege cada subdominio, incluido el de correo.
- Desactiva XML-RPC si no lo usas y limita el acceso a
wp-login.phpcon límite de intentos y segundo factor. - Revisa los registros al menos para detectar picos y rutas raras.
Un consejo de bajo valor: cambiar el prefijo de las tablas de la base de datos no frena nada de lo que vi aquí. Está bien como detalle, pero no lo priorices.
Limitaciones
- Cada fuente trae solo las últimas 1.000 filas de su registro, no el historial completo. Por eso el firewall cubre 9,3 días y el access log, que anota cada visita, solo 4,3 horas.
- Es un solo sitio; no se generaliza.
- El access log cubre solo 4,3 horas, y no se pueden comparar volúmenes con el firewall.
- El export indica el tipo de regla de cada evento pero no la regla exacta; las reglas de ejemplo de la tabla son ilustrativas. Las firmas de CVE (PHPUnit, PHP-CGI, Vite) son inferidas a partir de las rutas.
- 17 eventos figuran con IP de loopback; probablemente una mala atribución detrás de un proxy o un escaneo desde el propio servidor. Los dejé en los conteos.
- La clasificación de clientes se basa en User-Agent y rutas (heurística), y los User-Agents son falsificables.
- El proveedor solo se identifica con rangos publicados de nube; el resto puede ser residencial u otro hosting.
- La hora está tal como se registra, sin zona horaria indicada.
Conclusión
Lo que se teme (adivinar contraseñas) casi no apareció. Lo que llegó fue automatización barata buscando lo que alguien dejó donde no debía. Eso es buena noticia: la defensa más eficaz es de orden y de mantenimiento, no de magia.
Si quieres que revise tu sitio WordPress, audite qué está expuesto y lo endurezca, escríbeme a contact@camilordz.com.
Fuentes
- Patchstack, State of WordPress Security in 2026 (datos de 2025).
- NIST NVD, CVE-2017-9841.
- NIST NVD, CVE-2024-4577.
- Datos propios: exportaciones de eventos de firewall (4 al 13 de octubre de 2026) y access log (13 de octubre de 2026) de un sitio WordPress en producción, anonimizadas.
Ideas, sistemas y lecturas de diseño web que merecen ser probadas
¿Hostinger es bueno? Mi experiencia de 5 años con dominios, WordPress y VPS, más ventajas, desventajas, precios de renovación, soporte y si sirve para ecommerce.
Segunda parte de la guía de Git para vibe coders: qué son las ramas y cómo usarlas para cada experimento con IA, cómo resolver un conflicto de merge y cuándo usar git restore, reset, revert o reflog para deshacer errores sin perder trabajo.
Guía sencilla de Git para quienes programan con IA: qué es un sistema de control de versiones, la diferencia entre Git y GitHub, las tres áreas de Git, el flujo básico (init, add, commit, log) y una rutina para que el agente no te destruya el proyecto.



