WP-Cron es el sistema de tareas programadas de WordPress. No es un cron del sistema operativo: WordPress revisa “en cada carga de página” qué eventos están vencidos y, si corresponde, los ejecuta durante esa misma carga.

Esto implica dos consecuencias directas:

  • Es dependiente de tráfico: si no hay visitas, tareas pueden ejecutarse tarde.
  • La ejecución de tareas puede ocurrir “en contexto de una request web”, lo que afecta tiempos de respuesta y consumo de recursos si hay mucho trabajo acumulado.

Además, WordPress documenta que es común “enganchar WP-Cron al scheduler del sistema” haciendo una request periódica a wp-cron.php, y que, si hacemos eso, debemos deshabilitar la ejecución automática en cada carga porque ya no es necesaria y consume recursos extra.

Traducción operativa: que wp-cron.php responda públicamente (200) no es raro: es un endpoint funcional. El problema aparece cuando se convierte en un vector de abuso por frecuencia.

📌 Guía completa: Seguridad WordPress (checklist + prioridades).

✅ Acción rápida: Iniciar auditoría gratis y recibir evidencias en minutos.


1) Riesgos reales: DoS/abuso y degradación operativa

1.1 DoS por “frecuencia”, no por “contenido malicioso”

El patrón típico de abuso no requiere explotar una vulnerabilidad clásica: basta con forzar muchas ejecuciones o forzar el chequeo/arranque continuo del cron para aumentar CPU/DB/IO y degradar el servicio.

WP-Cron puede revisar tareas en cada carga y ejecutar las debidas durante la request.
Si un actor automatiza llamadas a wp-cron.php o induce ejecuciones con alta frecuencia, la carga puede dispararse.

1.2 Efectos comunes que observamos en producción

  • Aumento de consumo de CPU/PHP-FPM y consultas a base de datos durante ventanas de abuso.
  • Tiempos de respuesta inconsistentes (picos) por “colas” de eventos.
  • Eventos cron que se solapan o se reintentan por fallos intermitentes (efecto bola de nieve).
  • Ruido operacional: logs llenos de hits a wp-cron.php y dificultad para separar tráfico legítimo del abusivo.

1.3 Riesgo adicional: dependencia de plugins

Muchos plugins programan tareas (backups, envíos, sincronizaciones, feeds, limpieza). Si se ejecutan con demasiada frecuencia o con concurrencia accidental, el coste se multiplica. Por eso el endurecimiento debe preservar fiabilidad y control.


2) Cómo evaluar el impacto con evidencia (no con suposiciones)

Paso 1 — Confirmar exposición y patrón de invocación

  • Verificar si https://su-dominio.tld/wp-cron.php responde y si existe el patrón ?doing_wp_cron= en logs (muy habitual).
  • WordPress incluye funciones para detectar si una request es “cron request” (wp_doing_cron()), útil para instrumentación y diagnóstico.

Paso 2 — Medir frecuencia real y correlación con carga

  • En access logs/WAF/CDN: conteo por minuto de hits a wp-cron.php.
  • En métricas: correlación con CPU, PHP workers, DB load, latencias.

Paso 3 — Inspeccionar la cola de eventos programados

Recomendamos utilizar WP-CLI cuando sea posible:

  • wp cron event list para listar eventos
  • wp cron test para probar el sistema de “spawning” del cron
    La documentación oficial de WP-CLI describe estos comandos y su objetivo.

Paso 4 — Identificar tareas “caras”

Con la lista de eventos, buscamos:

  • tareas con alta frecuencia,
  • tareas que deberían ser horarias/diarias pero aparecen cada minuto,
  • tareas de plugins de terceros con consumo elevado.

3) Estrategias de endurecimiento (de menor a mayor impacto)

Estrategia A — Mantener wp-cron.php público, pero con rate limiting (control de abuso)

Cuándo aplica: no tenemos acceso a cron del sistema o necesitamos compatibilidad máxima.

  • Aplicamos rate limiting por ruta wp-cron.php.
  • Excluimos (o tratamos distinto) orígenes conocidos (monitorización interna, servidor) si existe.

Ventaja: no cambia el funcionamiento de WordPress.
Limitación: sigue existiendo superficie; solo reducimos el abuso.

Estrategia B — Mover la ejecución a cron del sistema y desactivar el “spawn” en cada visita (recomendación estándar)

WordPress recomienda: si vamos a programar una ejecución periódica desde el scheduler del sistema, entonces debemos deshabilitar WP-Cron en cada carga, porque ya no es necesario y consume recursos.

Esto se realiza normalmente con la constante DISABLE_WP_CRON en wp-config.php (práctica ampliamente usada y coherente con la guía oficial de “hooking WP-Cron into the system scheduler”).

Ventajas:

  • Controlamos frecuencia (cada 1, 5, 10 minutos… según necesidad).
  • Menos carga acoplada a visitas.
  • Más previsibilidad y estabilidad.

Riesgos:

  • Si olvidamos crear el cron del sistema, las tareas dejarán de ejecutarse en tiempo.

Estrategia C — Restringir acceso a wp-cron.php (solo localhost / red de confianza) + cron del sistema

Cuándo aplica: buscamos minimizar superficie pública y tenemos control del servidor o del edge.

  • Permitimos acceso a wp-cron.php solo desde:
    • loopback (127.0.0.1) o
    • IPs del reverse proxy/CDN (si el cron se ejecuta desde ahí)
  • Bloqueamos el resto.

Ventaja: reduce superficie y abuso casi por completo.
Riesgo: debemos asegurar que el cron del sistema llama a wp-cron.php desde un origen permitido.

Estrategia D — Ejecutar eventos con WP-CLI en lugar de hacer request web (cuando procede)

WP-CLI ofrece gestión de cron (listar, ejecutar, testear).
Cuando el entorno lo permite, ejecutar cron vía WP-CLI reduce dependencia de llamadas HTTP y puede simplificar restricciones en el edge.


4) Implementación práctica: cron del sistema, WP-CLI, restricciones y WAF/rate-limit

4.1 Deshabilitar el “spawn” automático (paso 1)

En wp-config.php, establecemos la constante para que WP-Cron no se dispare en cada visita (dejaremos la ejecución al cron real). WordPress indica que, una vez programado el scheduler, es mejor deshabilitar el disparo por carga para evitar uso extra de recursos.

Importante: este cambio exige el Paso 2 (cron real). Si no, las tareas se retrasarán indefinidamente.

4.2 Programar cron del sistema (paso 2)

WordPress documenta como solución “más fácil” programar el scheduler del sistema para hacer una request periódica a wp-cron.php.

Recomendación operativa (frecuencia):

  • Sitio con tráfico moderado: cada 5 minutos suele ser suficiente.
  • Sitio con colas sensibles (e-commerce, membresías): cada 1 minuto puede ser razonable, según carga.

4.3 Alternativa recomendada: cron con WP-CLI (paso 2 bis)

Cuando WP-CLI está disponible:

  • wp cron event run --due-now (ejecutar lo vencido)
  • wp cron test para validar “spawning” y estado
    La referencia oficial de WP-CLI describe los subcomandos y su finalidad.

Ventaja: menos dependencia de HTTP y más control en entorno servidor.

4.4 Restringir acceso a wp-cron.php (paso 3)

Una vez que el cron real está operativo (y probado), podemos restringir el endpoint:

  • A nivel servidor (Nginx/Apache): permitir solo IP/localhost.
  • A nivel WAF/CDN: permitir solo origen interno o aplicar challenge/bloqueo al resto.

Esta es la medida que más reduce abuso, siempre que el origen legítimo esté bien definido.

4.5 WAF / rate limiting (capa de contención)

Aunque restrinjamos, es recomendable mantener:

  • rate limit para requests a wp-cron.php desde Internet (si no lo bloqueamos al 100%),
  • alertas ante spikes,
  • y exclusiones controladas para el origen legítimo.

5) Checklist de cierre (criterios de aceptación)

Consideramos el riesgo de wp-cron.php público correctamente gestionado cuando:

Evaluación

  • Hemos medido hits a wp-cron.php y correlación con carga (antes/después).
  • Hemos inventariado eventos cron con WP-CLI (lista y “test”).

Mitigación

  • WP-Cron no se ejecuta en cada visita porque hemos delegado en un scheduler (recomendación oficial).
  • Existe cron real (HTTP o WP-CLI) con frecuencia definida y monitorizada.
  • wp-cron.php está rate-limited o restringido por IP/origen (según escenario).
  • Se han validado tareas sensibles (publicación programada, emails, backups, colas) tras el cambio.

Verificación

  • wp_doing_cron() y/o logs confirman que las ejecuciones son las esperadas (no picos anómalos).

6) Preguntas frecuentes

¿wp-cron.php público es “una vulnerabilidad”?

Por sí solo, normalmente es una superficie más que un “bug”. El riesgo principal suele ser abuso por frecuencia y degradación de recursos, porque WP-Cron se revisa y puede ejecutar tareas en contexto de requests.

¿Desactivar WP-Cron rompe el sitio?

No, si lo reemplazamos por un cron real. WordPress recomienda explícitamente que, si usamos el scheduler del sistema, deshabilitemos el disparo por carga para evitar uso extra de recursos.

¿Qué opción recomendamos por defecto?

En la mayoría de entornos profesionales:

  1. Delegar a cron del sistema (o WP-CLI)
  2. Deshabilitar ejecución por visita
  3. Restringir o rate-limitar wp-cron.php
    Este enfoque está alineado con la documentación oficial de WordPress sobre WP-Cron y su integración con el scheduler del sistema.