Seguridad WordPress 2026: RCE en Imagick, JSON remoto y plugins vibe-coded
ES

Seguridad WordPress 2026: RCE en Imagick, JSON remoto y plugins vibe-coded

Última verificación: 25 de agosto de 2026
19 min de lectura
Guía
500+ proyectos WP
Auditor de seguridad

CVE-2026-65640 exige Autor, Imagick y Ghostscript a la vez. Si falta cualquiera de las tres, esa ruta no existe. Los escáneres de ficheros siguen sin ver la clase siguiente: PHP que evalúa JSON que acaba de descargar.

WordPress 7.0.4 salió el 12 de agosto de 2026. Fue la tercera publicación de seguridad del núcleo en cuatro semanas (7.0.2 el 17 de julio, 7.0.3 el 6 de agosto). El CVE es ejecución remota de código autenticada a través de un fichero que parece una imagen. Lo reportó pwn.ai. El parche inspecciona el contenido antes de Imagick. Los backports llegan hasta 4.7.

Esta pieza cubre esa ruta, la ruta JSON que los escáneres no hashean, y los plugins que pasaron de un chat a producción. La auditoría de seguridad WordPress es la superficie comercial. El endurecimiento de runtime (passkeys, disco de solo lectura, WAF en el edge) está en la guía de hardening. No mezcles las dos.


#Imagick, Ghostscript y Author

ImageMagick procesa más que JPEG. PostScript, EPS y PDF van a Ghostscript. WordPress, a través de Imagick, elegía el manejador por la extensión. Imagick leía después los bytes. Un .png que es PostScript llegaba a Ghostscript. Eso es CVE-2026-65640 (CVSS 8.8, CWE-434).

Las dos cosas tienen que cumplirse:

  1. Imagick y Ghostscript están instalados y se usan para medios.
  2. Un usuario que puede subir (Autor y por encima) no es de confianza plena.

Un host solo con GD queda fuera de esta ruta. Imagick sin Ghostscript queda fuera de esta ruta. Subidas solo de Administrador, con dos personas que conoces, es otro riesgo.

Autor es el rol que importa. Blogs invitados, agencias, “el becario publica”. La generación de miniaturas corre al subir. Nadie abre el fichero en una aplicación de escritorio.

En el admin en español el rol se llama Autor. La capacidad es upload_files. Colaborador, de fábrica, no sube. Editor y Administrador también suben. El CVE no pide Administrador. Pide a alguien que pueda dejar un fichero en la biblioteca de medios y que WordPress le genere tamaños.

7.0.4 cambia WP_Image_Editor_Imagick::load() para mirar el contenido, rechazar firmas PostScript y EPS, PDF falsos, archivos que Imagick desempaquetaría, y prefijos de manejador. Ese es el arreglo del núcleo. No sustituye a policy.xml en el host.

El flujo concreto, en un sitio que no ha parcheado, es corto. El Autor entra en /wp-admin/media-new.php o arrastra un fichero al editor. WordPress acepta multipart/form-data, guarda el original en wp-content/uploads/AAAA/MM/ y pide a WP_Image_Editor_Imagick las miniaturas. Imagick mira la extensión, ve .png, abre los bytes, encuentra PostScript y llama al delegado Ghostscript. Ghostscript corre con el uid del pool PHP-FPM. Ahí acaba la autenticación HTTP. Lo que queda es una biblioteca C en el servidor.

En agencias de Madrid y Barcelona el patrón es viejo: el cliente quiere publicar él mismo las noticias, la agencia no quiere darle Administrador, y Autor parece el compromiso. El intern de marketing de una revista en Zaragoza sube “fotos del equipo” cada lunes. WooCommerce en un .es de moda pide recortes nítidos de producto, el hosting activa Imagick “porque GD se ve peor”, y Ghostscript entra en el servidor como dependencia del paquete ImageMagick. Nadie pidió PDF. El apt lo trajo igual.

Raiola, dinahosting y muchos VPS con Plesk en Debian instalan ImageMagick-6 con delegados de PostScript encendidos. Lo vemos en php -m y en which gs. Si las dos salidas tienen texto, el CVE aplica en cuanto exista un Autor que suba.

GD-only es la excepción útil. Algunos hosts PHP baratos nunca instalaron Imagick. Ahí CVE-2026-65640 no tiene delegado que llamar. Parchea igual: el aviso es AND para esta ruta, no una excusa para retrasar 7.0.4. El siguiente fallo de medios puede no pedir Ghostscript.

Imagick sin gs en PATH también corta esta ruta. Menos frecuente. El paquete imagemagick de Debian suele tirar de ghostscript. Quien desinstaló gs a propósito ya hizo, en la práctica, medio policy.xml.

La tabla de decisión es esta:

ImagickGhostscriptQuién sube¿Ruta CVE-2026-65640?
No (solo GD)IrrelevanteAutorFuera de esta ruta
NoAutorFuera de esta ruta
Solo Administradores conocidosRuta abierta, radio menor
Autor, Editor, invitado, becarioRuta abierta, radio real

CVSS 8.8 asume autenticación de Autor, no anónima. CWE-434 es subida sin restricción de tipo peligroso: la extensión miente, los bytes mandan. El parche del núcleo deja de creerse la extensión. El host todavía decide qué códecs existen.


#Ghostscript en policy.xml

Esta es la decisión de operación. El núcleo ahora inspecciona la subida. El host sigue decidiendo qué códecs de ImageMagick existen.

En Debian y Ubuntu el fichero suele ser /etc/ImageMagick-6/policy.xml o ImageMagick-7. Deniega los delegados que no necesitas:

<policy domain="coder" rights="none" pattern="PS" />
<policy domain="coder" rights="none" pattern="EPS" />
<policy domain="coder" rights="none" pattern="PDF" />
<policy domain="coder" rights="none" pattern="URL" />
<policy domain="coder" rights="none" pattern="HTTPS" />

Un plugin de seguridad no puede escribir ese fichero. Wordfence no sustituye la política de Ghostscript. Un WAF ve multipart/form-data de un Autor con sesión. No ve la biblioteca C después de que PHP aceptó la parte.

disable_functions para exec, shell_exec, passthru, system, proc_open es una segunda valla. No detiene Ghostscript si Imagick lo llama en el mismo proceso. Trátalo como útil, no como suficiente.

Los pools PHP-FPM compartidos significan que un RCE con éxito es el usuario del pool, a menudo el mismo usuario que el resto de sitios de la cuenta. Por eso Autor en un alojamiento compartido es otra conversación que Autor en un VPS de un solo inquilino. El CVE no cambia. El radio de explosión sí.

En Plesk, el PHP handler del dominio suele ser FPM con un uid por suscripción. Una suscripción con doce sitios WordPress (la web de la agencia, tres clientes, un staging olvidado) comparte ese uid. Ghostscript no pregunta qué vhost originó la miniatura. Escribe donde el uid pueda escribir. wp-config.php de los doce entra en el mismo radio.

En un VPS propio el uid suele ser www-data o un usuario de pool por sitio. Ahí un RCE sigue siendo grave. No salta a la cuenta del vecino. Los registros, las copias y el secreto de las cookies de ese sitio sí.

policy.xml vive fuera de WordPress. Un Administrador que instala plugins no lo toca. Un “optimizador de imágenes” del repositorio no lo toca. El de sistemas lo edita, recarga PHP-FPM, y comprueba con identify o con un PostScript de prueba que el códec responde not authorized. Si el test aún convierte, el fichero no es el que Imagick está leyendo. ImageMagick-6 e ImageMagick-7 conviven en algunos hosts. Mira phpinfo() y el valor ImageMagick compiled with.

PDF en WordPress no exige el códec PDF de ImageMagick. Los PDF de la biblioteca de medios se sirven como fichero. Las miniaturas de PDF, si las necesitas, son un producto aparte. Casi ninguna tienda .es las necesita. Casi todos los ImageMagick las tienen encendidas.

URL y HTTPS en policy.xml cortan a ImageMagick cuando intenta abrir un recurso remoto. No son el CVE de agosto. Son la misma clase: el binario hace más de lo que WordPress pidió. Los deniegas el mismo día.

Parchea primero. Luego policy.xml. Luego decide si Autor debe subir.


#JSON que no toca el disco

Los plugins de integridad comparan PHP con los checksums del zip de wordpress.org. Eso caza un webshell dejado en wp-content/uploads. No caza:

  • un feed de “novedades” que el plugin lee con file_get_contents y luego interpola en eval o en una plantilla con {php}
  • una lista remota de “presets de layout” que se decodifica y se pasa a restos de create_function
  • un comprobador de actualizaciones que ejecuta un phar desde la CDN del fabricante

El disco está limpio. El runtime no. El usuario administrador que aparece el martes lo creó una carga que nunca estuvo en git.

No tenemos una cifra pública de “siete plugins” que sea nuestra para citar. La clase basta: si el comportamiento útil del plugin llega por HTTPS desde un host que no fijas, trátalo como entrada ejecutable. Fija la URL, fija el hash, o quita el plugin.

JSON no es el enemigo. wp_remote_get más json_decode más salida escapada está bien. El fallo es decodificar y ejecutar.

En auditorías de sitios .es el patrón se parece. Un maquetador visual trae “plantillas del fabricante” al abrir el panel. El PHP del plugin no cambió desde el zip de wordpress.org. El JSON de templates.ejemplo.com/v2/list sí. Un escáner de Wordfence o de iThemes compara ficheros. El feed no es un fichero. Checksum verde, cuenta nueva en wp_users.

Los avisos de “what’s new” en la portada de wp-admin entran en la misma clase cuando el plugin concatena el cuerpo en eval o en assert. Un changelog renderizado con esc_html no. Abre el PHP y busca eval, assert, create_function, preg_replace con modificador /e, y include de un string que salió de json_decode.

Fijar la URL no es teatro. Un hash de la respuesta en un option, comparado antes de cualquier interpolación, convierte el feed en datos. Sin hash, el fabricante (o quien resuelva hoy ese DNS) publica código en tu PHP-FPM. El CDN del fabricante no es tu git.

Los phar remotos son peores. Un “updater” que descarga un archivo y lo include es instalación de software sin el flujo de wordpress.org. Trátalo como nuevo plugin, no como aviso.

Los transients ayudan a no martillar el origen. No firman el contenido. Un transient de 12 horas con JSON malicioso es 12 horas de payload en objeto, aún sin tocar disco.

Si el plugin solo pinta HTML escapado de un manifiesto versionado, déjalo. Si el plugin construye PHP o SQL a partir de ese manifiesto, fuera.


#Plugins vibe-coded en producción

Un chat que emite un zip de plugin es más rápido que una revisión. Producción no premia lo rápido.

Lo que seguimos abriendo en esos zips:

  • $wpdb->query("… $sin_sanear …") sin $wpdb->prepare
  • file_get_contents de una URL del fabricante en admin_init
  • update_option de un blob JSON entero llegado por POST, sin comprobación de capacidad más allá de read
  • CSS volcado en línea, que es un problema de vitals, no un RCE, y se publica igual porque nadie lo miró

La guía de hardening es el runtime. Esta sección es el suministro de PHP nuevo. Lockfile de Composer más una lectura de eval y de descargas remotas antes de que el plugin entre en producción. La autoinstalación desde el panel es cómo el código vibe-coded se salta esa lectura.

Los Autores que pueden subir son también la condición de CVE-2026-65640. Un plugin de formularios vibe-coded que otorga Autor a “clientes que envían historias” recrea la ruta de Imagick a propósito.

El zip típico que llega un viernes por la tarde, en una agencia que cierra antes de WordCamp Madrid, se llama cliente-formulario-v3.zip. El prompt fue “haz un plugin que guarde el formulario en una CPT y mande el correo”. El modelo escribió $wpdb->query con la superglobal concatenada, un admin_post sin check_admin_referer, y un wp_mail al Autor. Nadie corrió phpcs con las reglas de WordPress. Nadie buscó eval. El cliente publica. El intern, que ya es Autor para las noticias, ahora también es Autor porque el plugin lo crea al primer envío.

CSS inútil no ejecuta código. Sí retrasa LCP en móviles de red limitada, que en España sigue siendo el tráfico de muchas landing. Lo mencionamos porque el mismo zip que no prepara SQL suele traer 40 KB de utilidades Tailwind copiadas a admin_head. La revisión que caza una cosa caza la otra.

update_option de un JSON de POST con capacidad read es persistencia para quien pueda iniciar sesión, incluido un Autor. Al día siguiente el option se lee en init y se interpola. Disco sigue limpio. Runtime no.

Composer con composer.lock no es moda. Es la lista de lo que realmente corre. Un plugin “de chat” no tiene lockfile. Copia de Guzzle de hace tres años, copia de una función http_get propia, y un file_get_contents a HTTP sin TLS. La lectura previa a producción busca eso en diez minutos: eval, assert, create_function, unserialize de entrada, $wpdb->query con variables, file_get_contents/curl a hosts que no son wordpress.org, move_uploaded_file sin wp_check_filetype_and_ext.

Si el zip pasa esa lectura y tiene tests, puede entrar en staging. Producción es después de staging. El atajo “es un plugin pequeño” es cómo el vibe-coding salta el control.

Autores no son el enemigo. Autores con upload_files más Imagick más Ghostscript más un plugin que crea Autores son un producto distinto al que creías haber vendido.


#Qué cambia esta semana

  1. wp core version. Si estás por debajo de 7.0.4 en la línea 7.0, o te falta el backport en 6.x / 4.7+, parchea.
  2. php -m | grep imagick y si existe gs. Si ambos, policy.xml hoy.
  3. Lista de plugins: cualquier cosa que cargue un “feed” o “plantillas” del fabricante en el panel. Abre el PHP. Si evalúa, fuera.
  4. Lista de roles: cuántos Autores pueden subir. Corta a los que solo redactan borradores.
  5. Logs fuera de la caja, desde la guía de hardening. Un RCE que borra auth.log en el mismo disco es una conjetura, no un incidente.

No instales un segundo escáner como respuesta a un delegado de biblioteca. Los escáneres hashean ficheros.

El orden importa. El núcleo 7.0.4 (o el backport) cierra la extensión mentirosa en WP_Image_Editor_Imagick::load(). policy.xml cierra el delegado aunque el siguiente CVE se parezca. Quitar eval remoto cierra una clase que el parche de agosto no toca. Bajar Autores a Colaborador reduce la superficie de subida sin esperar a sistemas.

En un sitio en producción el viernes, no hagas las cinco a la vez sin copia. Parche del núcleo primero: es reversible y está en el flujo que ya usas. policy.xml segundo, con un PostScript de prueba. Roles tercero, hablando con quien publica. Plugins cuarto, con staging si el maquetador visual es el que pinta la home. Logs fuera de la caja el lunes, no como teatro del viernes.

wp core version miente si alguien dejó define('WP_VERSION'…) o un must-use que pinta otra cifra. Mira también version.php y el panel en Actualizaciones. El backport a 6.8 o a 4.7 no se llama 7.0.4. Se llama el paquete de seguridad de esa rama, publicado en la misma tanda de agosto. Si tu host retrasa el núcleo “porque un plugin de reservas no declara 7.0”, aplica el backport de tu rama y abre ticket al plugin. El CVE no espera a ese plugin.

Para Ghostscript, which gs no basta en jaulas raras. convert -list delegate | grep -i ps enseña si ImageMagick tiene el delegado. Si gs no está y el delegado sí, Imagick todavía puede llamar a Ghostscript por ruta compilada. policy.xml corta el códec con independencia del PATH.

No hace falta un plugin nuevo de “auditoría Imagick”. Hace falta el parche, el fichero de política, y una lista de usuarios. El resto es ruido de marketplace.


#El WAF no ve Imagick

Cloudflare, y cualquier WAF de aplicación, ve un POST autenticado a medios. Ve cookies, nonce, multipart/form-data, un nombre de fichero que acaba en .png. Clasifica la petición como tráfico de un Autor con sesión hacia async-upload.php o media-new.php. Eso es exactamente lo que un redactor hace un lunes. El WAF no tiene motivo para cortar.

Ghostscript no habla HTTP. Corre después de que PHP aceptó el fichero, lo escribió en uploads y se lo pasó a Imagick. En ese momento la petición ya obtuvo 200. El edge ya cerró. El proceso que importa es una biblioteca C en el uid de PHP-FPM. Ninguna regla gestionada de OWASP en Cloudflare mira ese proceso.

Un WAF no sustituye a policy.xml. El parche 7.0.4 inspecciona bytes en PHP, antes de Imagick. policy.xml deniega el códec en el host, aunque PHP se equivoque. El WAF opera un paso antes, en la petición. Los tres no son equivalentes. El WAF es el que menos ve esta ruta.

Las reglas gestionadas cazan webshells en POST anónimos, scanners de eval(base64_decode, login brute force, XML-RPC pingback. Un Autor logado que sube un PNG no parece nada de eso. Si el cuerpo multipart es grande, muchos planes ni lo inspeccionan entero. Cloudflare documenta límites de inspección de cuerpo. Una imagen de 2 MB los cruza. El PostScript disfrazado viaja en esa parte.

En sitios .es el patrón operativo empeora el agujero. El editor de un maquetador visual va lento con Bot Fight Mode. La agencia pide una Skip Rule para /wp-admin/* “porque si no Elementor no carga”. La Skip Rule se publica. El WAF deja de ver justo la ruta de subida autenticada. El proxy naranja sigue. El titular cree que “estamos detrás de Cloudflare”. Imagick y Ghostscript no se enteran.

Virtual patching en el edge puede, en teoría, buscar firmas PostScript dentro de un PNG. En la práctica casi nadie escribe esa regla, y la que existe se salta con un encabezado PNG válido y el payload más adentro. El núcleo 7.0.4 mira firmas de contenido con conocimiento de los manejadores de Imagick. El WAF mira strings. No es el mismo trabajo.

Una regla custom que exija que /wp-admin/async-upload.php solo acepte image/jpeg por Content-Type no cierra CWE-434. El navegador y el cliente HTTP mandan el tipo que quieren. El CVE vive en los bytes, no en la cabecera.

Una regla que bloquee .ps, .eps y .pdf en el nombre de fichero tampoco. El ataque usa .png.

Una regla que niegue la subida a Autores es, en realidad, un control de WordPress: quitar upload_files o bajar a Colaborador. Hacerlo en el WAF es duplicar un rol que ya existe, peor, porque el WAF no conoce el rol. Conoce la cookie. La cookie de un Editor y la de un Autor se parecen.

Dónde sí sirve el WAF, y por eso no se apaga: XML-RPC anónimo, xmlrpc.php de enumeración, fuerza bruta en wp-login.php, paths de plugins abandonados, relleno de comentarios. Eso está en la guía de hardening. No es CVE-2026-65640. Mezclarlos es cómo un informe de “WAF en verde” sustituye a policy.xml.

Control¿Ve el POST HTTP?¿Ve Ghostscript?¿Sigue útil en el próximo CVE parecido?
WAF / CloudflareSí, si no hay Skip Rule en wp-adminNoSolo si el próximo fallo es un patrón HTTP conocido
Núcleo 7.0.4Sí, en PHP, al cargar la imagenNo ejecuta el delegado si rechaza el contenidoHasta el siguiente bypass de firmas
policy.xmlNoCorta el códec en el hostSí: el delegado no existe
Colaborador sin subidaReduce quién hace el POSTNo llega a ImagickSí, para esta clase

El orden de trabajo no cambia porque tengas Cloudflare. Parche del núcleo. policy.xml. Roles. El WAF se revisa para quitar Skip Rules de /wp-admin/* que se publicaron por un editor lento, no para “virtual-parchear Imagick”.

Si el hosting es compartido y no te dejan tocar policy.xml, el WAF no cubre el hueco. Cambia de plan, de uid, o de host. Un ticket a Raiola o a dinahosting pidiendo los códecs PS/EPS/PDF/URL/HTTPS a none es el trabajo. Un plan Pro de Cloudflare no es ese ticket.

Headless tampoco es el WAF. Un front en Astro o en HTML estático quita PHP anónimo del catálogo público. wp-admin sigue en el origen. La mediateca sigue en el origen. El Autor sigue subiendo al origen. Imagick sigue en el origen. El WAF delante del front no ve esa subida si wp-admin va por otro hostname, que es el dibujo habitual. policy.xml sigue mandando.


#Auditoría y lecturas

La auditoría de seguridad es Imagick/Ghostscript, Autor, JSON remoto, y el zip de plugin que no leíste. Passkeys, disco de solo lectura y WAF de edge se quedan en el hardening avanzado.

CVE-2026-65640 es una ruta. policy.xml es el control que sigue importando cuando se publique el siguiente fallo parecido. JSON que se ejecuta es otra ruta. Los zips vibe-coded son una tercera. Una ficha de plugin que dice “protegido” no cubre ninguna por sí sola.

En la auditoría pedimos tres cifras, no un pantallazo de Wordfence. Versión de PHP. Si Imagick está cargado. Cuántos Autores suben. Con eso se decide si CVE-2026-65640 es urgente o calendario. Luego se abre el PHP de los plugins que pintan feeds. Luego se lee policy.xml o se documenta que el host no deja tocarlo. El informe nombra el uid del pool y cuántos sitios lo comparten. Sin eso, “RCE autenticado” es una etiqueta, no un radio.

INCIBE recoge incidentes de empresas españolas. No sustituye policy.xml. Si ya hay una cuenta administradora que no creaste, trata el origen como comprometido: rotación de secretos, copias fuera, no “otro escáner”. Los logs que viven en el mismo disco que PHP-FPM no son prueba. Por eso la guía de hardening saca los logs de la caja.

Lectura mínima de código, la misma semana: WP_Image_Editor_Imagick::load() en el núcleo que corres, el policy.xml real (no el de un tutorial), y tres plugins del panel que hablen de plantillas o de novedades. Si no puedes leer esos tres, no estás en condiciones de afirmar que el JSON no se evalúa.


#Conclusión

Tres publicaciones de seguridad del núcleo en cuatro semanas es el ritmo, no un eslogan. La de agosto pide Autor, Imagick y Ghostscript. Parchea el núcleo. Deniega los códecs de Ghostscript en el host. Deja de evaluar JSON remoto. Mantén fuera de producción los plugins exportados de un chat hasta que alguien los lea. El WAF ve el POST. No ve Imagick. Si quieres que se inspeccione, escribe con la versión de PHP, si Imagick está cargado, y cuántos Autores suben.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Hace falta un parche de emergencia en todos los sitios por CVE-2026-65640?#
Si Imagick y Ghostscript están los dos en uso y hay Autores en los que no confías del todo, sí. Si solo corres GD, actualiza en el calendario normal y parchea igual. El aviso es AND, no OR.
¿Por qué los escáneres de ficheros no vieron los ataques de feeds JSON?#
Hashean PHP en disco. Los bytes maliciosos llegaron en un documento JSON descargado. El disco no cambió.
¿Basta un WAF contra el RCE de Imagick?#
No. La subida es un POST autenticado a medios que parece una imagen. El trabajo peligroso es Ghostscript en el servidor, después de que PHP ya ha aceptado el fichero.
¿Pueden quedarse los Autores en el sitio?#
Sí, con la capacidad de subida revisada. Colaborador sin subida es el control más barato si solo redactan borradores.
¿Un WordPress headless elimina este RCE?#
Quita PHP anónimo del catálogo. wp-admin y la subida de medios siguen ejecutando PHP. Los Autores siguen subiendo. policy.xml sigue importando.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados