2026年11月12日
2026年11月12日
Ocultar la versión de WordPress: generator, ver= y readme.html
Este artículo es una edición localizada del original en japonés. Leer el original en japonés
En su estado inicial, WordPress escribe su número de versión en el HTML de las páginas y en los feeds. Un atacante puede usarlo como pista para comprobar si es una versión con vulnerabilidades conocidas. En este artículo se comprueba dónde aparece la versión y se explican los pasos para ocultarla. El contenido corresponde a octubre de 2026.
Lo primero que conviene saber es que ocultar la versión es solo una medida de apoyo. También hay maneras de deducir la versión, por ejemplo por el contenido de los archivos CSS y JavaScript, así que ocultarla no siempre impide que se la identifique. Lo que más eficacia tiene es mantener actualizados el núcleo de WordPress, los plugins y los temas.
Dónde se muestra la versión
| Lugar | Qué se muestra | Solución |
|---|---|---|
<head> del HTML |
Una etiqueta como <meta name="generator" content="WordPress 6.9.4"> |
Filtro the_generator |
| Feeds RSS y Atom | Una línea como <generator>https://wordpress.org/?v=6.9.4</generator> |
También el filtro the_generator |
| URL de CSS y JavaScript | Un ?ver= como style.min.css?ver=6.9.4 |
Filtros style_loader_src y script_loader_src |
| Cabeceras HTTP | X-Powered-By: PHP/8.3.x (la versión de PHP, no la de WordPress) |
expose_php en php.ini |
readme.html |
Que se usa WordPress (el readme.html actual no incluye el número de versión) | Denegar el acceso |
La información del sitio que devuelve /wp-json/ de la REST API (nombre, descripción, URL, zona horaria, espacios de nombres, etc.) no incluye la versión de WordPress. No hace falta recortar la salida de la REST API para ocultar la versión.
Paso 1: comprobar lo que se muestra ahora
Sustituye la URL por la de tu sitio y ejecútalo en tu ordenador o en el servidor. Si usas plugins de caché o una CDN, vacía la caché después de los cambios antes de comprobar.
# Etiqueta generator del HTML
curl -s https://example.com/ | grep -i 'name="generator"'
# generator del feed
curl -s https://example.com/feed/ | grep -i '<generator>'
# Lista de valores de ver= que llevan el CSS y el JS
curl -s https://example.com/ | grep -oE 'ver=[0-9][0-9.]*' | sort | uniq -c
# X-Powered-By en las cabeceras HTTP
curl -sI https://example.com/ | grep -i 'x-powered-by'
# ¿Se puede leer readme.html? (si devuelve 200, se puede)
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/readme.html
Si en la lista de ver= aparece el mismo valor que la versión de WordPress que se muestra en "Escritorio" (Dashboard) → "Actualizaciones" (Updates) del panel de administración, significa que con ese CSS o JS se puede conocer la versión de WordPress. Cuando el núcleo de WordPress o el tema cargan CSS y JS sin indicar una versión, la versión de WordPress acaba en ver=.
Paso 2: decidir dónde poner el código
El código de este artículo se coloca en uno de estos dos sitios.
- mu-plugin (recomendado): si colocas un archivo PHP en la carpeta
wp-content/mu-plugins/(créala si no existe), se carga sin necesidad de activarlo. El efecto continúa aunque cambies de tema - functions.php de un tema hijo: si lo escribes en el functions.php del tema padre, se pierde al actualizar el tema
Si lo haces como mu-plugin, guarda el código del siguiente paso en un solo archivo con un nombre como wp-content/mu-plugins/hide-wp-version.php.
Paso 3: ocultar la etiqueta generator y la versión de ver=
<?php
/**
* Plugin Name: Hide WordPress Version
* Description: Oculta la versión de WordPress que aparece en la etiqueta generator y en el ver= de CSS y JS.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Vaciar el <meta name="generator"> del HTML y el <generator> de los feeds.
add_filter( 'the_generator', '__return_empty_string' );
/**
* Solo cuando el ver= de CSS y JS es igual a la versión de WordPress, sustituirlo por otro valor.
* Como se sustituye y no se elimina ver=, la caché del navegador se renueva tras actualizar WordPress.
*/
function wpdr_replace_wp_version_query( $src ) {
if ( ! is_string( $src ) || '' === $src ) {
return $src;
}
$query = wp_parse_url( $src, PHP_URL_QUERY );
if ( empty( $query ) ) {
return $src;
}
parse_str( $query, $args );
$wp_version = get_bloginfo( 'version' );
if ( isset( $args['ver'] ) && $args['ver'] === $wp_version ) {
$src = add_query_arg( 'ver', substr( wp_hash( $wp_version ), 0, 10 ), $src );
}
return $src;
}
add_filter( 'style_loader_src', 'wpdr_replace_wp_version_query', 20 );
add_filter( 'script_loader_src', 'wpdr_replace_wp_version_query', 20 );
Los puntos clave son estos.
- El filtro
the_generatoractúa tanto en la etiqueta generator del HTML como en el generator de los feeds.remove_action( 'wp_head', 'wp_generator' );solo elimina la etiqueta del HTML, así que no afecta a los feeds - Si eliminas todos los
?ver=, al actualizar plugins o temas el navegador puede seguir usando el CSS y el JS antiguos. El código anterior solo sustituye el valor cuando coincide con la versión de WordPress, por una cadena distinta generada a partir de esa versión. Al actualizar WordPress el valor también cambia, de modo que la caché se renueva - No se modifican los
ver=a los que los plugins o los temas ponen su propio número de versión
Cuando lo hayas guardado, comprueba con los comandos del paso 1 que ya no aparece generator y que en la lista de ver= no queda la versión de WordPress. Si usas plugins de caché, vacía la caché antes de comprobar.
Paso 4: detener la cabecera X-Powered-By
X-Powered-By es una cabecera que añade PHP, no WordPress, y deja ver la versión de PHP. Para detenerla, pon expose_php en Off en el archivo de configuración de PHP (php.ini). Este ajuste solo se puede cambiar en php.ini.
expose_php = Off
Este es un ejemplo con PHP-FPM en Ubuntu en un VPS (el 8.3 debe coincidir con la versión de PHP que uses).
# Comprobar el ajuste actual
grep -n '^expose_php' /etc/php/8.3/fpm/php.ini
# Tras modificarlo, reiniciar PHP-FPM
sudo systemctl restart php8.3-fpm
El php.ini de los paquetes de Ubuntu viene con expose_php = Off en su estado inicial. Si la cabecera aparece, comprueba que no se esté usando otro php.ini. En los servidores de alojamiento compartido, a veces se puede cambiar desde los ajustes de PHP del panel y a veces no.
Si no puedes cambiar php.ini, también hay una manera de quitar la cabecera desde el código de WordPress. Sin embargo, send_headers es un hook que se ejecuta cuando WordPress muestra las páginas del front-end, por lo que no afecta al panel de administración ni a la pantalla de inicio de sesión.
add_action( 'send_headers', function () {
header_remove( 'X-Powered-By' );
} );
Paso 5: denegar el acceso a readme.html y license.txt
readme.html y license.txt son archivos del núcleo de WordPress. El readme.html actual no incluye el número de versión, pero deja ver que se usa WordPress.
Aunque los borres, vuelven al actualizar el núcleo de WordPress. Es menos trabajo denegar el acceso en el servidor web que borrarlos.
Con Apache (.htaccess)
Añádelo al .htaccess de la carpeta de WordPress. Lo que queda entre # BEGIN WordPress y # END WordPress lo reescribe WordPress, así que escríbelo fuera de ese bloque. Es la sintaxis de Apache 2.4 (Order y Deny from all son la sintaxis antigua de Apache 2.2).
<FilesMatch "^(readme\.html|license\.txt)$">
Require all denied
</FilesMatch>
Con Nginx
Añádelo al bloque server del sitio, comprueba la configuración y vuelve a cargarla.
location ~* ^/(readme\.html|license\.txt)$ {
deny all;
}
sudo nginx -t && sudo systemctl reload nginx
Tras añadirlo, ejecuta curl -s -o /dev/null -w '%{http_code}\n' https://example.com/readme.html y comprueba que devuelve 403.
Lo que ocultar no evita
- El contenido de los archivos CSS y JS de WordPress cambia un poco en cada versión, así que se puede deducir la versión descargando los archivos y comparándolos
- A veces se puede conocer la versión de los plugins a partir del
readme.txto delver=de los plugins y los temas. Lo que más se ataca son las vulnerabilidades de los plugins más que las del núcleo - Para quien puede iniciar sesión en el panel de administración, la versión se sigue mostrando como siempre
Por eso, además de ocultar la versión, actualiza el núcleo, los plugins y los temas, elimina los plugins que no uses y desactiva la edición de archivos desde el panel de administración, entre otras medidas.
Resumen
- La versión se muestra principalmente en el generator del HTML y de los feeds y en el
?ver=de CSS y JS. El/wp-json/de la REST API no incluye la versión de WordPress - Con
add_filter( 'the_generator', '__return_empty_string' );se elimina el generator tanto del HTML como de los feeds - Si no eliminas
?ver=y solo sustituyes el valor igual a la versión de WordPress, no detienes la renovación de la caché X-Powered-Byse detiene conexpose_php = Offen php.inireadme.htmlvuelve tras las actualizaciones aunque lo borres, así que deniega el acceso en el servidor web- Ocultarla es una medida de apoyo; lo más importante es seguir actualizando
Artículos relacionados:
- Cómo configurar las cabeceras de seguridad de WordPress: .htaccess, Nginx y functions.php
- Cómo restringir el acceso a la REST API de WordPress
- Desactivar el editor de archivos de temas y plugins de WordPress: DISALLOW_FILE_EDIT
¿Dudas sobre WordPress? Quien publica este sitio está en Japón y responde en japonés. Contacto (en japonés)