CVE-2026-87902 en WordPress: RCE en get_page_template() y cómo parchear ya
TL;DR — Lo que vas a tener al final
- Tiempo de setup: 30 minutos para instalación, 1-2 horas para upgrade in-place.
- Requisitos: Backup de /home, conexión a internet, 20+ GB libres.
- Resultado: Sistema actualizado con soporte extendido, drivers funcionando.
- Troubleshooting: dnf distro-sync, akmods para NVIDIA, journalctl -p err.
Qué acaba de pasar
El 22 de septiembre de 2026, el equipo de seguridad de WordPress publicó la versión 7.1.2 con un parche para una vulnerabilidad crítica: CVE-2026-87902. La falla está en get_page_template(), una función central que decide qué archivo de tema usar para mostrar una página. Un atacante sin autenticar puede manipular el parámetro page con una secuencia ../ doblemente codificada (%252f) y forzar a WordPress a hacer include de un archivo PHP arbitrario fuera del directorio del tema activo. Si en ese servidor existe un archivo PHP legible con contenido controlado — un log envenenado, un upload aceptado por otro plugin, un archivo de sesión — el LFI escala a RCE completo.
La investigadora suiza Robert Ressl reportó el bug de forma responsable a través del programa de divulgación de WordPress. El equipo lo confirmó, asignó CVSS v4.0 9.2 (crítico), y distribuyó el fix a la rama 7.1 y, como cortesía, a todas las ramas desde 4.7 hasta la 6.9. Eso es 25 versiones distintas con parche: 7.1.2, 7.0.6, 6.9.9, 6.8.10, 6.7.9, 6.6.9, 6.5.12, 6.4.12, 6.3.12, 6.2.13, 6.1.14, 6.0.16, 5.9.18, 5.8.17, 5.7.19, 5.6.21, 5.5.22, 5.4.23, 5.3.25, 5.2.28, 5.1.26, 5.0.29, 4.9.33, 4.8.32, 4.7.37.
Patchstack reportó que intentos de reconocimiento aparecieron en logs menos de cinco horas después del disclosure. La ventana entre anuncio y explotación se mide en horas, no en días.
Por qué este LFI escala a RCE (y cuándo no)
Lo crítico del aviso no es la inclusión en sí, sino el camino de la inclusión a ejecución. La función get_page_template() construye una ruta desde el slug de la página, y un input malicioso puede escapar del directorio wp-content/themes/<theme>/ mediante ../. El detalle que la detección convencional pasa por alto es la doble codificación: el payload viaja como %252f (que decodifica a %2f, luego a /), evade la sanitización superficial de WordPress, y recién es procesado por el resolver de templates, que completa la escalada.
El LFI en sí es cierto: cualquier sitio en una versión afectada permite a un anónimo incluir un archivo PHP local. Para llegar a RCE hace falta una condición adicional: que exista en el servidor un archivo PHP legible con código que el atacante controle. Tres vectores típicos:
pearcmd.php, el binario PEAR histórico que muchas imágenes Docker de PHP incluyen en/usr/local/lib/php/pearcmd.php. Combinado conregister_argc_argv=Onpermite inyectar código vía parámetros-d. La imagen oficialphpde Docker viene conregister_argc_argv=Onpor defecto.- Logs envenenados: si PHP acepta
User-Agentu otro header en access logs, y el atacante logra meter código PHP en una request normal antes de la explotación, luego incluye el log vía LFI. - Archivos de sesión PHP: si el sitio tiene un formulario vulnerable que escribe a
/tmp/sess_*, un payload previo en un campo del form queda embebido en la sesión y es includible.
El aviso oficial lista temas cuya estructura de directorios facilita el ataque. Si tu tema activo tiene un directorio de primer nivel cuyo nombre empieza con page- — por ejemplo page-templates/ — el camino vulnerable queda expuesto. Se mencionan Twenty Twelve, Twenty Fourteen, Neve, Hestia y Sydney. Verifica esto en tu instalación, no asumas que el nombre del tema es indicador suficiente.
Tu servidor: ¿está en riesgo?
El primer chequeo es de versión. Si tu wp-includes/version.php dice algo menor al parche de tu rama, estás vulnerable:
# Compara la versión corriendo con la versión parcheada de tu rama
ssh usuario@servidor 'cd /var/www/wordpress && wp core version --allow-root'
# Debería decir: 7.1.2 (rama actual) / 7.0.6 / 6.9.9 / etc
# Si dice 7.1.1, 7.1.0, o cualquier <X.Y.Z> sin el parche, ERES vulnerable
El segundo chequeo es de tema. Lista los directorios de primer nivel del tema activo:
# Tema parent activo
ssh usuario@servidor 'ls -la /var/www/wordpress/wp-content/themes/<tu-tema>/ | head -20'
# Tema child (si usas)
ssh usuario@servidor 'ls -la /var/www/wordpress/wp-content/themes/<tu-child>/ | head -20'
# Busca cualquier carpeta que empiece con "page-"
ssh usuario@servidor 'find /var/www/wordpress/wp-content/themes/ -maxdepth 2 -type d -name "page-*"'
El tercer chequeo es de entorno PHP, especialmente si corres en Docker o cPanel:
# ¿Está register_argc_argv activo?
ssh usuario@servidor 'php -r "echo ini_get("register_argc_argv");"'
# "1" = vulnerable al chain pearcmd.php. "0" = mitigado.
# ¿Existe pearcmd.php accesible vía LFI?
ssh usuario@servidor 'ls -la /usr/local/lib/php/pearcmd.php 2>/dev/null || find / -name pearcmd.php 2>/dev/null'
Si los tres retornan vulnerables — versión sin parche, tema con page-*/, y pearcmd accesible — el riesgo de RCE es real. El vector pearcmd.php combinado con el LFI es la cadena más explotada históricamente en este patrón de bug, y la imagen oficial php de Docker no mitiga ninguna de las dos condiciones.
Cómo parchear hoy, sin importar tu versión
Si corres WordPress en una sola instalación accesible:
# Backup primero
ssh usuario@servidor 'cd /var/www/wordpress && wp db export /tmp/wp-pre-712.sql --allow-root'
ssh usuario@servidor 'cd /var/www/wordpress && tar czf /tmp/wp-files-pre-712.tar.gz wp-content/ wp-includes/ wp-admin/'
# Core update menor seguro (preserva archivos wp-content y wp-config.php)
ssh usuario@servidor 'cd /var/www/wordpress && wp core update --allow-root'
ssh usuario@servidor 'cd /var/www/wordpress && wp core update-db --allow-root'
# Confirma que el patch llegó
ssh usuario@servidor 'cd /var/www/wordpress && wp core version --allow-root'
Si administras un multisite o un farm de sitios con múltiples versiones, el panorama es más complejo. WordPress distribuye el parche a 25 ramas distintas, y la rama 4.7 todavía recibe updates de seguridad — eso es una rareza. La estrategia correcta en multisite:
# Lista qué versión corre cada sitio del farm (ejemplo: multisite principal)
ssh usuario@servidor 'cd /var/www/wordpress && wp site list --fields=url,registered --allow-root --format=table'
# Para cada sitio, actualiza a la versión parcheada de SU rama:
# - WordPress 7.0 → 7.0.6
# - WordPress 6.5 → 6.5.12
# - WordPress 5.4 → 5.4.23
# El flag --minor preserva tu rama, sólo sube el patch number
ssh usuario@servidor 'cd /var/www/wordpress/wp-admin && wp core update --minor=7.0.6 --version=7.0.6 --allow-root'
# Después de cada update, confirmar
ssh usuario@servidor 'cd /var/www/wordpress && wp core version --allow-root'
Si tu sitio está gestionado por un panel (cPanel, Plesk, RunCloud, GridPane) y no tienes shell, casi todos ya ofrecen el parche en su update queue. Verifica que tu plan de mantenimiento los aplique de forma automática — y si no lo hace, abre un ticket con tu proveedor hoy. No esperes al próximo ciclo de mantenimiento.
Mitigaciones de emergencia si no puedes parchear aún
Hay escenarios donde el parche no se puede aplicar de inmediato: sitios en producción que requieren ventanas de mantenimiento, conflictos con plugins custom, o deployments que todavía no tienen aprobación de QA. En esos casos, mitiga en cuatro capas, todas reversibles cuando llegue el parche:
- Bloquea el payload en la capa WAF/reverse proxy. El request malicioso incluye un
page=con secuencias de%anidadas. Una regla ModSecurity o equivalente con regex que detecte%25repetido en parámetros de query string corta la mayoría de intentos automatizados. - Desactiva
register_argc_argven php.ini. Esto cierra el vector más fácil de pearcmd.php. Cambio reversible, sin downtime:register_argc_argv = Off+ reload de PHP-FPM. - Elimina o renombra
pearcmd.phpsi tu distribución lo incluye. Las imágenes Docker oficiales lo traen en/usr/local/lib/php/pearcmd.php. Moverlo o cambiarle los permisos cierra el LFI-to-RCE. - Monitorea logs por patrones de la cadena de explotación: requests con
page=+%252fo%252e%252e+ unpage_idválido. Wordfence Premium y Care publicaron reglas el 22-sep; los usuarios Free las reciben el 22-oct.
# Mitigación 1: Apache mod_rewrite para cortar doble encoding antes de pasar a PHP
# En tu .htaccess del blog, agrega (antes de los rewrite de WP):
# <IfModule mod_rewrite.c>
# RewriteEngine On
# RewriteCond %{QUERY_STRING} (page=[^&]*%252[fFeE]) [NC]
# RewriteRule .* - [F,L]
# </IfModule>
# Mitigación 2: register_argc_argv off
echo "register_argc_argv = Off" >> /etc/php/8.3/fpm/php.ini
sudo systemctl reload php8.3-fpm
# Verifica
php -r 'echo ini_get("register_argc_argv") . PHP_EOL;' # debería decir 0 u Off
Estas mitigaciones NO reemplazan el parche. Son puente hasta que puedas ejecutar el update de Core en producción. Algunas cadenas de ataque que no usan pearcmd.php (por ejemplo, log poisoning) siguen funcionando aunque cortes el vector de PEAR.
Cómo verificar que tu sitio NO fue comprometido durante la ventana
Si tu sitio estuvo expuesto entre el 22-sep-2026 (publicación del advisory) y el día que aplicaste el parche, asume que un atacante pudo haber dejado webshells. El check mínimo:
# 1. Busca archivos PHP sospechosos en directorios donde WP no debería escribir
ssh usuario@servidor 'find /var/www/wordpress/wp-content/uploads -name "*.php" -ls 2>/dev/null'
ssh usuario@servidor 'find /var/www/wordpress/wp-includes -newer /tmp/patch-timestamp -name "*.php" -ls 2>/dev/null'
# 2. Revisa los logs de acceso por la firma del exploit
# Firma: page= con doble encoding + un page_id válido
ssh usuario@servidor 'grep -E "page=[^&]*%25" /var/log/apache2/access.log | tail -20'
ssh usuario@servidor 'grep -E "page=[^&]*%25" /var/log/nginx/access.log | tail -20'
# 3. Comprueba que no haya usuarios administradores nuevos
ssh usuario@servidor 'cd /var/www/wordpress && wp user list --role=administrator --allow-root --format=table'
# Compara contra tu último backup de usuarios admin conocidos
# 4. Busca tareas cron sospechosas vía WP-Cron (los atacantes suelen plantar cron jobs persistentes)
ssh usuario@servidor 'cd /var/www/wordpress && wp cron event list --allow-root --format=table | head -50'
Si alguna de estas retorna hits, no entres en pánico pero sí escala. Cambia contraseñas de admin, rota salts en wp-config.php (define AUTH_KEY, SECURE_AUTH_KEY, etc — usa wp config shuffle-salts --allow-root), y considera restaurar desde un backup pre-ventana si encuentras un webshell.
Versiones afectadas y cuándo parchear cada una
| Rama WordPress | Versiones vulnerables | Versión parcheada |
|---|---|---|
| 7.1 | 7.1.0 — 7.1.1 | 7.1.2 |
| 7.0 | 7.0.0 — 7.0.5 | 7.0.6 |
| 6.9 | 6.9.0 — 6.9.8 | 6.9.9 |
| 6.8 | 6.8.0 — 6.8.9 | 6.8.10 |
| 6.7 | 6.7.0 — 6.7.8 | 6.7.9 |
| 6.6 | 6.6.0 — 6.6.8 | 6.6.9 |
| 6.5 | 6.5.0 — 6.5.11 | 6.5.12 |
| 6.4 | 6.4.0 — 6.4.11 | 6.4.12 |
| 6.3 | 6.3.0 — 6.3.11 | 6.3.12 |
| 6.2 | 6.2.0 — 6.2.12 | 6.2.13 |
| 6.1 | 6.1.0 — 6.1.13 | 6.1.14 |
| 6.0 | 6.0.0 — 6.0.15 | 6.0.16 |
| 5.9 y anteriores | hasta 5.9.17 | 5.9.18 y backports disponibles |
La rama 4.7, la más antigua soportada, recibe parche 4.7.37 — eso significa que el equipo de seguridad sigue manteniendo ese árbol después de casi nueve años. Es un dato positivo en un mar de malas noticias.
Vale la pena actualizar hoy
Sí, sin discusión. La razón no es sólo esta vulnerabilidad. WordPress 7.1 trae consigo 26 parches acumulados en su changelog menor 7.1.x, además del fix crítico. Si vienes de 6.x, hay mejoras de rendimiento en block editor, soporte oficial de PHP 8.5, y compatibilidad con el nuevo Theme.json v3. Si vienes de 5.x o 4.x, además hay cambios de schema en la base de datos y deprecaciones que tu tema y plugins deben absorber.
El caso atípico es ClassicPress, el fork de WordPress. El aviso confirma que ClassicPress todavía no distribuyó un parche al momento de publicación del advisory en LWN. Si administras un sitio en ClassicPress, monetizar o exponer datos importantes en esa plataforma es un riesgo no cuantificable hoy. Evalúa migrar a WordPress estándar o aplicar el parche upstream manualmente si tienes el equipo para mantener una rama custom.
Conclusión
CVE-2026-87902 es exactamente el patrón clásico de LFI-to-RCE en PHP: input mal validado que llega a include, condición ambiental que lo convierte en shell. La doble codificación es lo que lo hizo sobrevivir a las defensas existentes; los temas con directorios page-*/ son la condición de la que depende el camino vulnerable. El vector pearcmd.php en imágenes Docker oficiales es lo que lo hace práctico y reproducible — y lo que hace crítico que cualquier sysadmin que corra WordPress en Docker actualice ya, o al menos mitigue register_argc_argv.
Si tienes sitios propios o de clientes en WordPress, este es el tipo de patch que se aplica hoy, no mañana. El equipo de seguridad distribuyó el fix a 25 ramas simultáneamente, lo cual baja el costo operativo al mínimo. La excusa “todavía no me toca actualizar la rama 4.7” ya no aplica.
Preguntas frecuentes
¿Por qué CVE-2026-87902 en WordPress: RCE en get_page_template() y cómo parchear ya es relevante para sysadmins Linux?
Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.
¿Qué necesito para empezar con CVE-2026-87902 en WordPress: RCE en?
Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.
¿Cuáles son los errores más comunes con CVE-2026-87902 en WordPress: RCE en?
Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.
¿Cuándo usar CVE-2026-87902 en WordPress: RCE en y cuándo una alternativa?
Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.
¿Cómo migro desde una configuración previa a CVE-2026-87902 en WordPress: RCE en?
Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.
Lee también
- Guía Fedora 44: Novedades, Instalación y Upgrade para Sysadmins Linux
- Configura VLANs en Linux con nmcli: Guía paso a paso para sysadmins
- Protege tu SSH: Guía esencial para configurar Fail2ban en Linux
- Guía Definitiva: Configura Kubernetes con kubeadm en Ubuntu para Sysadmins Linux
- Configura Prometheus y Grafana: Guía DevOps para SysAdmins Linux
