En la primera parte del artículo analizamos los errores más comunes a nivel conceptual y técnico que suelen afectar a la seguridad de cualquier instalación WordPress, especialmente en sus primeras fases.
En esta segunda parte nos centraremos en errores más avanzados, aquellos que suelen pasar desapercibidos en entornos ya consolidados, y que pueden convertirse en puertas de entrada críticas para atacantes. Además, al final del artículo encontrarás una checklist descargable para auditar la seguridad de tu WordPress paso a paso.
- Usuarios con acceso a configuraciones críticas
- Modo depuración habilitado
- Revelar información sensible a través del readme
- Funciones de depuración activas en producción
- Mantener permisos de archivo y carpetas inseguros
- Dejar archivos ocultos accesibles
- Permitir ejecución de PHP en /uploads
- Listado de directorios habilitado
- REST API sin restricciones
- Cabeceras HTTP inseguras o mal configuradas
- SSO o JWT mal implementados
- Copias de seguridad no cifradas
- Backups guardados en el servidor de producción
- Logs no protegidos
- Dar acceso a terceras personas
- Ignorar avisos de seguridad
- Checklist de seguridad en WordPress
Usuarios con acceso a configuraciones críticas
Muchas instalaciones de WordPress otorgan a editores o colaboradores más permisos de los necesarios, especialmente cuando se instalan plugins que añaden menús en el panel como:
- Ajustes de SEO (Yoast, Rank Math, All in One SEO)
- Gestión de formularios (WPForms, Gravity Forms, Ninja Forms)
- Creación de backups (UpdraftPlus, All-in-One WP Migration, Jetpack Backup)
- Gestión de caché o seguridad
Esto permite a usuarios no técnicos realizar acciones peligrosas sin control: borrar formularios, modificar redirecciones, cambiar políticas de indexación o restaurar un backup antiguo.
Errores que suelen cometerse:
- Asignar roles altos sin verificar las capacidades reales necesarias.
- No auditar los menús disponibles para cada rol.
- Usar plugins que no permiten granularidad en los permisos.
- Suponer que los roles por defecto limitan el acceso a funciones de plugins (no siempre es así).
Por qué es un problema
- Un editor puede sin querer marcar una web como no indexable.
- Un colaborador podría restaurar una copia antigua y perder contenido.
- Un plugin mal diseñado puede permitir a roles no administradores editar configuraciones sensibles.
- En multisite o tiendas WooCommerce, los accesos mal gestionados escalan el problema.
Solución paso a paso
1. Revisar roles y capacidades con un plugin
Algunos plugins, como Members o User Role Editor, permiten:
- Ver qué capacidades tiene cada rol
- Editar o quitar el acceso a plugins específicos
- Crear roles personalizados como «Editor SEO» o «Gestor de formularios»
2. Controlar el menú visible con plugins como:
Puedes ocultar partes del panel que no debe ver cada rol, sin tocar el core de WordPress ni los plugins.
3. Usar plugins que respeten capabilities
Antes de instalar un plugin de SEO, backup o formularios, verifica:
- ¿Qué rol puede ver sus ajustes?
- ¿Se puede limitar el acceso?
- ¿Usa
manage_options,edit_posts,custom_capability?
Revisa la documentación o prueba en staging para saber qué expone.
4. Validar accesos en staging antes de activarlo en producción
- Crea un usuario con rol limitado
- Navega por el admin y comprueba qué opciones aparecen
- Asegúrate de que no puede hacer más de lo necesario
Desde WP-CLI
Puedes ver todos los roles y capacidades:
wp role listwp cap list editor
Y eliminar una capacidad:
wp cap remove editor edit_forms
Buenas prácticas adicionales
- Usa roles personalizados en proyectos medianos y grandes.
- Documenta quién puede hacer qué.
- No des acceso a configuraciones críticas sin formación previa.
- Actualiza los permisos cuando cambien las responsabilidades.
- Revoca accesos cuando alguien deja de colaborar.
Controlar el acceso a configuraciones clave evita errores catastróficos causados por despistes o desconocimiento.
Modo depuración habilitado
WordPress cuenta con un sistema de depuración que, cuando está activado, muestra errores y avisos directamente en pantalla o los guarda en archivos. Esto es muy útil en desarrollo, pero puede suponer un riesgo grave de seguridad en producción si se deja activo por descuido.

Por qué es peligroso
- Los errores pueden mostrar rutas internas del sistema (carpetas, archivos).
- Se pueden exponer credenciales, tokens o información sensible.
- Un atacante puede usar esa información para explotar vulnerabilidades.
- Afecta a la experiencia de usuario si se muestran avisos en el frontend.
Cómo solucionarlo
Comprueba si está activo buscando esta línea en wp-config.php:
define( 'WP_DEBUG', true );
Si aparece como true, el modo de depuración está activo.
Configuración recomendada para producción
define( 'WP_DEBUG', false );define( 'WP_DEBUG_LOG', false );define( 'WP_DEBUG_DISPLAY', false );
Incluso si necesitas registrar errores, deberías usar:
define( 'WP_DEBUG', true );define( 'WP_DEBUG_LOG', true );define( 'WP_DEBUG_DISPLAY', false );
Esto guarda los errores en el archivo wp-content/debug.log sin mostrarlos al usuario.
Plugins que pueden ayudar:
- Query Monitor: solo visible para administradores, ideal para desarrollo.
- WP Debugging: permite activar y desactivar opciones de debug desde el admin.
Desde WP-CLI
Puedes verificar y modificar la configuración:
wp config get WP_DEBUGwp config set WP_DEBUG false --raw
Y lo mismo para las constantes WP_DEBUG_LOG y WP_DEBUG_DISPLAY.
Buenas prácticas adicionales
- Nunca dejes activo
WP_DEBUGen entornos de producción. - Usa entornos staging o locales para probar y depurar.
- Automatiza la validación del
wp-config.phpen tu flujo de despliegue. - Si necesitas logs, asegúrate de que no son accesibles vía web (
.htaccess, reglas Nginx).
El modo de depuración es esencial para el desarrollo, pero dejarlo activo en producción puede ser un regalo para los atacantes.
Revelar información sensible a través del readme
Hasta versiones recientes, el archivo readme.html que viene con WordPress mostraba la versión exacta de la instalación y algunos detalles sobre el CMS. Aunque a día de hoy ya no revela la versión (no se muestra desde la versión 5.8), sigue siendo un vector de reconocimiento para escáneres automatizados.
¿Por qué sigue siendo un problema?
- Es una forma rápida de confirmar que un sitio usa WordPress.
- Algunos bots lo usan como «fingerprint» para lanzar ataques específicos.
- Aunque no muestra la versión, puede servir como indicador de malas prácticas si sigue accesible.
- Puede dejar al descubierto otros archivos del core si no hay restricciones adicionales.
Cómo solucionarlo
Haz una comprobación rápida accediendo a:
https://tusitio.com/readme.html
Si se carga contenido, significa que el archivo sigue ahí y accesible desde fuera.
1. Eliminar el archivo manualmente
Por FTP, SFTP o desde terminal:
rm /ruta/a/tu/web/readme.html
2. Bloquear el acceso desde .htaccess (Apache)
<Files readme.html> Order Allow,Deny Deny from all</Files>
3. Bloquear el acceso desde Nginx
location = /readme.html { deny all; access_log off; log_not_found off;}
4. Usar un WAF o regla en Cloudflare
Puedes bloquear cualquier petición al archivo:
- Crear una regla en Cloudflare que diga: URI path contains readme.html → Block
¿Y qué pasa con la versión de WordPress?
Aunque el readme.html ya no la muestra, todavía se puede revelar por otros medios si no se controlan:
- En la cabecera HTML con:
<meta name="generator" content="WordPress 6.4.3" />
- En feeds RSS/Atom o sitemaps
- A través de archivos como
wp-includes/version.phpsi no están protegidos
Cómo ocultar la versión
En functions.php o en un plugin personalizado:
remove_action( 'wp_head', 'wp_generator' );
Y si usas Yoast SEO, asegúrate de que también lo elimina del sitemap.
Buenas prácticas adicionales
- Haz un escaneo automatizado tras cada actualización para detectar archivos del core accesibles.
- Usa herramientas como WPScan o Nessus para comprobar si se filtra la versión por otras vías.
- Monitoriza logs para detectar bots accediendo a
readme.htmlolicense.txt.
Aunque ya no muestre la versión, readme.html es una pista innecesaria que ayuda al reconocimiento de herramientas automáticas.
Funciones de depuración activas en producción
En entornos de desarrollo es habitual utilizar funciones como phpinfo() o herramientas como Xdebug para depurar problemas. Pero si estos elementos permanecen activos o accesibles en producción, representan una grave amenaza de seguridad.
Errores que se suelen cometer:
- Subir
info.phpy olvidarlo. - No desactivar
Xdebugen entornos de producción. - Usar
phpinfo()directamente en plugins o temas como prueba. - Permitir que el sistema de logs sea accesible desde la web.
Por qué es un riesgo
phpinfo()expone rutas de archivos, versiones exactas de PHP, módulos activos, variables de entorno, rutas de logs y más.Xdebug, si no está desactivado o filtrado correctamente, permite conexiones remotas o acceso a trazas de ejecución.- Muchos desarrolladores crean un archivo
info.phpcon el siguiente contenido y lo olvidan en producción:
<?php phpinfo();
Este archivo es escaneado por bots automáticamente y suele ser objetivo frecuente de auditorías externas.
Cómo solucionarlo
1. Eliminar cualquier archivo info.php
Desde la raíz del proyecto o usando terminal:
find /var/www/html -type f -name "info.php" -delete
2. Desactivar phpinfo() en producción
Edita el archivo php.ini correspondiente a tu versión activa:
disable_functions = show_source, system, shell_exec, passthru, phpinfo
Y reinicia el servicio:
sudo systemctl restart php8.3-fpm
Sustituye php8.3-fpm por tu versión real de PHP.
3. Desactivar Xdebug fuera de desarrollo
Ubica tu archivo de configuración de Xdebug (/etc/php/8.3/mods-available/xdebug.ini) y comenta su activación:
;zend_extension=xdebug.so
O usa comandos como:
phpdismod xdebugsudo systemctl restart php8.3-fpm
4. Verifica que no haya trazas o dumps accesibles
Evita rutas como:
/var/www/html/xdebug_output/- Archivos
.xto.tracepúblicos - Logs accesibles vía navegador
Auditoría desde terminal
Busca trazas sospechosas:
find wp-content -type f \( -name "*.log" -o -name "*.trace" -o -name "*.xt" \)
Y revisa si hay archivos con phpinfo() aún activos:
grep -Ri "phpinfo" .
Buenas prácticas adicionales
- Nunca uses
phpinfo()en entornos públicos. - Desactiva Xdebug al desplegar en producción.
- Incluye en tu checklist de despliegue la verificación de archivos de diagnóstico.
- Usa entornos locales o staging con acceso limitado para depuración.
- Configura el servidor para que no sirva archivos
.log,.trace,.inio.bak.
Un simple archivo info.php puede revelar más información de la que imaginas. Eliminarlo y desactivar Xdebug en producción es una tarea sencilla que reduce mucho la superficie de ataque.
Mantener permisos de archivo y carpetas inseguros
La configuración incorrecta de permisos en archivos y carpetas es uno de los errores más comunes (y peligrosos) en instalaciones WordPress. Permisos demasiado permisivos permiten a atacantes subir o modificar archivos, leer datos sensibles o ejecutar código malicioso.
Los errores más comunes son:
- Usar 777 para arreglar errores de permisos (solución rápida, pero insegura).
- Dejar permisos heredados de entornos locales o staging.
- No revisar los permisos tras restaurar un backup o migrar.
- Usar
chownochmodsin entender el impacto.
Por qué es un riesgo
- Archivos con permisos 777 permiten la lectura, escritura y ejecución por cualquier usuario.
- Carpetas con permisos demasiado abiertos pueden permitir la subida o modificación remota.
- Algunos servidores permiten ejecutar código PHP desde carpetas de uploads si no están correctamente configuradas.
- Permisos mal gestionados facilitan la escalada de privilegios o el acceso a
wp-config.php.
Permisos recomendados en WordPress
| Elemento | Permisos | Comentario |
|---|---|---|
| Archivos .php, .js, etc. | 644 | Lectura/escritura para dueño, lectura para el resto |
| Carpetas (wp-content, etc.) | 755 | Lectura/escritura/ejecución para dueño, lectura/ejecución para otros |
| wp-config.php | 640 o 600 | Solo accesible por el usuario del servidor |
El hosting que te da más
Desde backups en tiempo real hasta un tiempo de actividad insuperable. Todo lo que necesitas, sin restricciones.
Cómo aplicarlos correctamente
1. Establecer permisos seguros
Desde terminal:
find . -type d -exec chmod 755 {} \;find . -type f -exec chmod 644 {} \;chmod 600 wp-config.php
2. Asegurar propietario correcto (chown)
chown -R www-data:www-data /var/www/html/wordpress
Sustituye www-data y la ruta por los valores de tu entorno.
3. Verificar excepciones
- Plugins como WP Super Cache o W3 Total Cache pueden necesitar permisos adicionales en sus carpetas de caché.
- Algunos plugins crean carpetas temporales: verifica que no tengan permisos 777.
- En entornos compartidos, nunca dejes archivos con permisos de escritura global.
Automatiza auditoría de permisos
Puedes crear un pequeño script para verificar los permisos:
#!/bin/bashfind . -type f -perm 777 -exec echo "Archivo inseguro: {}" \;find . -type d -perm 777 -exec echo "Carpeta insegura: {}" \;
Y ejecutarlo periódicamente desde cron o con Monit/n8n.
Desde WP-CLI
Aunque no puede cambiar permisos directamente, puedes combinarlo con exec:
wp eval 'exec("find . -type f -perm 777")';
Buenas prácticas adicionales
- No uses permisos 777 nunca, ni temporalmente.
- Revisa permisos tras cada despliegue o restauración.
- Documenta los permisos base que debe tener el proyecto.
- Usa
umaskadecuada en tus scripts de despliegue. - Considera deshabilitar ejecución PHP en carpetas como
/uploads.
Una correcta configuración de permisos es clave para evitar intrusiones silenciosas y garantizar que solo el servidor puede modificar los archivos.
Dejar archivos ocultos accesibles
Muchos entornos de desarrollo o despliegue dejan archivos ocultos en la raíz del proyecto o en carpetas internas. Estos archivos pueden contener credenciales, rutas, tokens de API o configuraciones que un atacante puede aprovechar si son accesibles desde el navegador.

Archivos comunes que se deben proteger o eliminar:
.env: claves de API, datos de acceso a la base de datos, secretos..git/config,.git/HEAD: información del repositorio, historial, estructura..DS_Store: metadatos de macOS, pero delatan estructura..htaccess,.user.ini: reglas del servidor, configuraciones PHP.*.bak,*.old,*.zip,*.tar.gz: copias de seguridad o archivos temporales.debug.log,error.log,info.php: trazas, errores y herramientas de diagnóstico.
Por qué es peligroso
- Si un
.enves accesible, se pueden filtrar las credenciales de producción. - Algunos bots escanean específicamente estos archivos.
- Una copia
.bakdewp-config.phppuede exponer todo el sistema. .gitpermite incluso reconstruir archivos eliminados si no está protegido.
Solución paso a paso
Comprobar si hay archivos accesibles, accediendo a ellos mediante URL:
https://tusitio.com/.envhttps://tusitio.com/.git/confighttps://tusitio.com/wp-config.php.bak
- Usa escáneres automáticos como:
- Revisa tu servidor o backup con:
find . -type f \( -name ".*" -o -name "*.bak" -o -name "*.old" -o -name "*.zip" \)
Cómo bloquear el acceso a estos archivos
En Apache (.htaccess)
<FilesMatch "^\.(env|git|htaccess|user.ini|DS_Store|log)$"> Order allow,deny Deny from all</FilesMatch>
En Nginx
location ~* /(?:\.git|\.env|\.htaccess|\.user.ini|\.DS_Store|debug\.log) { deny all; access_log off; log_not_found off;}
En Cloudflare
Puedes crear una regla:
URI Path contains .env OR .git → Block
Buenas prácticas adicionales
- No subas
.envo.gita producción. - Elimina backups locales (
.zip,.tar.gz) tras usarlos. - Configura
.gitignorepara excluir archivos sensibles. - Usa entornos separados para desarrollo y producción.
- Revisa backups automáticos, plugins de migración o exportación que generen archivos
.sql,.json,.wpressvisibles.
Un solo archivo oculto mal protegido puede comprometer todo tu sistema.
Permitir ejecución de PHP en /uploads
La carpeta uploads de WordPress está pensada para almacenar archivos multimedia (imágenes, documentos, vídeos), pero nunca debería permitir la ejecución de código PHP. Sin embargo, si no se configura correctamente el servidor, es posible subir un archivo .php camuflado y ejecutarlo desde allí.
¿Por qué es tan peligroso?
- Un atacante que logre subir un
shell.phppuede ejecutar comandos directamente desde esa ruta. - Plugins mal desarrollados o formularios vulnerables pueden permitir subir archivos
.phpcon otro nombre o extensión doble (file.php.jpg). - La mayoría de los escaneos automáticos buscan exactamente esto.
Solución paso a paso
Comprobar si se puede ejecutar PHP
- Sube un archivo
info.phpcon este contenido awp-content/uploads:
<?php phpinfo();
- Accede desde el navegador a:
https://tusitio.com/wp-content/uploads/info.php
- Si se ejecuta, tu servidor permite PHP en esa carpeta. ¡Corrígelo inmediatamente!
Desactivar ejecución PHP
En Apache (.htaccess)
Crea un archivo .htaccess dentro de wp-content/uploads con:
<FilesMatch "\.(php|php\.|phtml)$"> Order Deny,Allow Deny from all</FilesMatch>
En Nginx
Agrega en tu bloque del sitio:
location ~* ^/wp-content/uploads/.*\.(php|php\.|phtml)$ { deny all; access_log off; log_not_found off;}
Recarga el servicio después de editar:
sudo systemctl reload nginx
Validaciones adicionales
- Asegúrate de que ningún plugin permita subir archivos
.php,.phtml,.phar. - Bloquea la ejecución de PHP en rutas inseguras.
- Usa reglas en Cloudflare/WAF para bloquear intentos de ejecución desde uploads.
Protección desde el servidor
- En servidores con
open_basedir, puedes restringir aún más la ejecución por ruta. - Usar
disable_functionsymod_securityayuda a bloquear payloads comunes.
Desde consola
Puedes hacer auditorías:
find wp-content/uploads -type f -name "*.php"
Buenas prácticas adicionales
- Automatiza revisiones semanales de archivos
.phpen uploads. - Si usas Amazon S3 o similar para medios, la ejecución ya está bloqueada por defecto.
- Monitoriza accesos a uploads en tus logs para detectar patrones sospechosos.
uploads debe ser un lugar seguro para imágenes y documentos, no un punto de entrada para código malicioso.
Listado de directorios habilitado
Cuando un directorio no contiene un archivo de índice (index.html, index.php, etc.), y el servidor lo permite, el navegador puede mostrar un listado completo de archivos dentro de esa carpeta. Este comportamiento es común en servidores mal configurados o tras despliegues incompletos.

Por qué es un problema
- Permite a cualquier visitante ver archivos internos de una carpeta.
- Puede revelar nombres de plugins, temas, backups, archivos temporales o incluso archivos
.sqlo.zipolvidados. - Facilita el reconocimiento de la estructura por parte de atacantes o bots automatizados.
Cómo comprobar si tienes el listado activo
- Accede a rutas como:
https://tusitio.com/wp-content/uploads/https://tusitio.com/wp-includes/
- Si ves un listado con enlaces a archivos, tienes el listado de directorios habilitado.
Cómo desactivar el listado de directorios
En Apache (.htaccess)
Agrega esta línea:
Options -Indexes
En Nginx
Asegúrate de que el bloque del sitio no tenga la directiva autoindex on;, y añade:
location / { autoindex off;}
Luego recarga el servidor:
sudo systemctl reload nginx
En Cloudflare o WAF
Este tipo de comportamiento no se bloquea desde Cloudflare directamente, pero puedes:
- Crear reglas que bloqueen accesos a rutas tipo
*/si no hay archivo solicitado. - Monitorizar el número de accesos a rutas tipo
/wp-content/uploads/
Alternativas preventivas
- Asegúrate de que todas las carpetas relevantes tienen al menos un
index.htmlvacío. - Algunos temas ya insertan estos archivos de forma automática.
- Si usas plugins que generan carpetas nuevas, verifica que no queden abiertas.
Auditoría automática
Desde la terminal puedes buscar carpetas sin archivo index.*:
find wp-content/ -type d ! -exec test -e "{}/index.php" \; -print
O detectar peticiones sospechosas en logs:
grep 'GET /wp-content/uploads/' /var/log/nginx/access.log | grep ' 200 '
Buenas prácticas adicionales
- No expongas carpetas internas como
/includes,/vendor,/private, etc. - Audita los nuevos directorios tras cada despliegue o instalación de un plugin.
- Configura las reglas en tu servidor web para desactivar el listado por defecto.
Evitar el listado de directorios es una de las configuraciones más básicas, pero aún se encuentra expuesto en miles de sitios WordPress.
REST API sin restricciones
Desde WordPress 4.7, el sistema incluye una REST API nativa que permite acceder y modificar contenido del sitio mediante peticiones HTTP. Aunque esta funcionalidad es muy potente para desarrollos headless, apps móviles o integraciones externas, si se deja sin restricciones puede convertirse en una vía de fuga de información o manipulación indebida.
Qué puede exponer la REST API por defecto
Algunas rutas abiertas por defecto:
/wp-json/wp/v2/users/wp-json/wp/v2/posts/wp-json/wp/v2/media/wp-json/wp/v2/comments
Estas rutas pueden:
- Mostrar todos los usuarios registrados (incluso sin estar logueado)
- Exponer contenido oculto (borradores de entradas, privados)
- Dejar que bots enumeren medios, taxonomías o endpoints personalizados
Por qué es un problema
- Muchos bots automatizados rastrean la ruta
/wp-json/wp/v2/userspara obtener los nombres de usuario reales del sitio. - Se puede utilizar para ataques de fuerza bruta o enumeración de roles.
- Algunos plugins exponen sus propios endpoints sin protección adecuada.
Cómo limitar el acceso a la REST API
1. Bloquear completamente el acceso anónimo
Desde el archivo functions.php o un MU-plugin:
add_filter( 'rest_authentication_errors', function( $result ) { if ( ! is_user_logged_in() ) { return new WP_Error( 'rest_forbidden', 'REST API desactivada para usuarios anónimos', array( 'status' => 403 ) ); } return $result;});
2. Permitir solo ciertas rutas
Puedes hacer una whitelist de endpoints permitidos según tu proyecto.
3. Usar un plugin de control de REST API
- Disable REST API
- Perfmatters, que incluye opciones para ocultar o limitar la REST API.
4. Limitar acceso vía servidor
En Nginx:
location ~* ^/wp-json/wp/v2/users { deny all;}
En Apache:
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_URI} ^/wp-json/wp/v2/users RewriteRule .* - [F,L]</IfModule>
Cómo auditar los accesos a la REST API
- Revisa logs de acceso:
grep "/wp-json/" /var/log/nginx/access.log
- Usa plugins como Query Monitor o Wordfence para ver qué endpoints están activos.
- Haz peticiones manuales con curl o Postman para comprobar las respuestas:
curl https://tusitio.com/wp-json/wp/v2/users
Buenas prácticas adicionales
- Si no usas la REST API, bloquéala.
- Si usas funcionalidades específicas (por ejemplo, WooCommerce), limita las rutas innecesarias.
- Añade un token o una capa de autenticación personalizada si necesitas exponer endpoints externos.
- Monitoriza la actividad sospechosa con herramientas como Fail2ban, Wordfence o Cloudflare.
La REST API es una de las herramientas más potentes de WordPress moderno, pero también una de las más mal utilizadas en términos de seguridad.
Cabeceras HTTP inseguras o mal configuradas
Las cabeceras HTTP (headers) son parte esencial de cualquier respuesta web. Permiten al navegador entender cómo comportarse con los recursos del servidor. Sin embargo, si se configuran incorrectamente o se dejan en su valor por defecto, pueden revelar información sensible o debilitar la protección contra ataques comunes.
Riesgos de no configurar las cabeceras:
- Revelar la versión del servidor web (Apache, Nginx, PHP): útil para fingerprinting.
- Permitir la ejecución de contenido inseguro (scripts, iframes, formularios externos).
- No bloquear ataques comunes como clickjacking, XSS o carga de recursos externos peligrosos.
Ejemplos de cabeceras sensibles o mal configuradas:
- Server: Apache/2.4.41 (Ubuntu) → revela tecnología y versión.
- X-Powered-By: PHP/7.4.33 → identifica versión exacta de PHP.
- Ausencia de:
- X-Frame-Options
- Content-Security-Policy
- X-Content-Type-Options
- Strict-Transport-Security
Solución paso a paso
Auditar las cabeceras HTTP, esto podemos hacerlo de diversas maneras:
1. Desde las DevTools del navegador:
- Abre las herramientas del navegador → pestaña Network.
- Selecciona la solicitud principal (/) → pestaña Headers → Response Headers.
2. Desde el terminal
curl -I https://tusitio.com
3. Con herramientas externas
Cabeceras recomendadas para producción
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadX-Content-Type-Options: nosniffX-Frame-Options: SAMEORIGINReferrer-Policy: strict-origin-when-cross-originPermissions-Policy: geolocation=(), microphone=()Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
Nota: CSP debe adaptarse a tu proyecto, ya que puede romper scripts o integraciones si no está bien definida.
Configurar cabeceras
En Nginx
add_header X-Frame-Options "SAMEORIGIN" always;add_header X-Content-Type-Options "nosniff";add_header Referrer-Policy "strict-origin-when-cross-origin";add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;add_header Permissions-Policy "geolocation=(), microphone=()";
En Apache
Header always set X-Frame-Options "SAMEORIGIN"Header set X-Content-Type-Options "nosniff"Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"Header set Referrer-Policy "strict-origin-when-cross-origin"Header set Permissions-Policy "geolocation=(), microphone=()"
Ocultar tecnologías utilizadas
- En Apache:
ServerTokens ProdServerSignature Off
- En PHP (
php.ini):
expose_php = Off
- En Cloudflare:
- Puedes eliminar cabeceras como Server y X-Powered-By desde su WAF o transform rules.
Monitorización y buenas prácticas
- Añade revisión de cabeceras a tu checklist de despliegue.
- Usa políticas progresivas para CSP (report-only + logs).
- Audita tus cabeceras tras instalar o actualizar plugins.
- Integra validaciones con herramientas como n8n.
Unas pocas cabeceras bien configuradas pueden bloquear ataques automatizados, proteger contenido y mejorar la puntuación de seguridad de tu sitio.
SSO o JWT mal implementados
En entornos donde se utiliza autenticación externa (Single Sign-On o tokens JWT), una mala implementación puede ser incluso más insegura que el sistema clásico de inicio de sesión por formularios.
Los errores más habituales se relacionan con:
- Tokens sin expiración o con duración excesiva.
- Tokens que no se validan correctamente (firma, payload o algoritmo).
- Falta de revocación en sesiones comprometidas.
- Almacenamiento inseguro del token (localStorage, sin HTTPOnly, sin Secure).
Qué riesgos implica
- Si un token no expira, cualquier atacante que lo robe podrá autenticarse indefinidamente.
- Si no se verifica correctamente el algoritmo o la firma (alg: none, firmas débiles), el token puede falsificarse.
- Si no hay validación del payload, se pueden asumir identidades o privilegios.
- Al guardar el token en localStorage, puede ser accedido por scripts maliciosos (XSS).
Ejemplo de token JWT vulnerable
{ "alg": "none", "typ": "JWT"}{ "user": "admin", "role": "administrator"}
Si el servidor acepta este token sin firma válida, cualquier usuario puede escalar privilegios.
Buenas prácticas con JWT en WordPress o headless
- Siempre utiliza firmas robustas (HMAC SHA256 o mejor).
- Define expiración razonable (exp) y revocación (jti, listas negras).
- Verifica cada token recibido en el servidor, no en el cliente.
- No guardes tokens en localStorage; usa cookies con HttpOnly y Secure si es posible.
- Usa librerías seguras como Firebase JWT o Auth0 SDK si implementas tu propio flujo.
En WordPress: plugins y librerías comunes
- JWT Authentication for WP REST API: permite autenticación vía tokens, pero debes configurar bien los headers y controlar los tiempos de expiración.
- Plugins SSO como SAML u OpenID también pueden quedar mal configurados si no validan correctamente el IDP.
Cómo auditar tu implementación
- Decodifica un JWT con jwt.io y revisa si contiene campos exp, iat, nbf, iss, aud, etc.
- Verifica cómo y dónde se guarda (¿localStorage?, ¿cookies inseguras?).
- Comprueba si hay validación del algoritmo de firma.
- Revisa si los tokens pueden revocarse.
Recomendaciones extra
- Usa rotación de tokens (refresh + access tokens) con expiración corta.
- Añade detección de anomalías en el comportamiento del token.
- Protege los endpoints sensibles con doble validación (por IP, user-agent, rate-limit).
- Asegúrate de que el token no viaja por correo, GET, ni se guarda en logs.
Los sistemas SSO y JWT bien implementados mejoran la seguridad y escalabilidad, pero una configuración negligente puede ser una puerta trasera muy difícil de detectar.
Copias de seguridad no cifradas
Las copias de seguridad son esenciales para cualquier proyecto WordPress, pero muchas veces se almacenan en formatos planos, sin cifrado, accesibles desde ubicaciones predecibles o con nombres identificables. Esto convierte los backups en objetivos valiosos para atacantes.
Errores comunes:
- Almacenar backups directamente en
/wp-content/uploads/o/backups/. - No usar contraseñas ni cifrado al exportar
.sql,.gz,.zip. - No revisar accesos a los backups almacenados en servidores, nubes públicas o carpetas compartidas.
Riesgos de no cifrar los backups:
- Acceso directo a base de datos con credenciales, correos, contraseñas hash.
- Descarga de archivos ZIP/TAR completos del sitio desde rutas predecibles (
/wp-content/backups/). - Exposición de usuarios, licencias, tokens de API, configuraciones sensibles (
wp-config.php).
Buenas prácticas para cifrado y seguridad de backups
1. Cifrar automáticamente con GPG o OpenSSL
# Backup y cifrado GPGmysqldump -u user -p dbname | gzip > backup.sql.gz# Cifradogpg --symmetric --cipher-algo AES256 backup.sql.gz
# Con OpenSSLopenssl enc -aes-256-cbc -salt -in backup.sql.gz -out backup.sql.gz.enc
2. Subir a almacenamiento externo cifrado
- pCloud con carpeta cifrada.
- Backblaze B2 con cliente que cifre de forma local.
- S3 con cifrado en cliente y bucket privado.
3. No usar rutas accesibles públicamente
- Nunca almacenes backups en carpetas servidas por el servidor web.
- Protege las carpetas con
.htaccesso reglas Nginx si no hay otra opción.
4. Nombres no identificables
Evita nombres como backup-wordpress.zip o web-sql.sql. Usa nombres ofuscados:
2024-10-31_wp_bk_98a2ff7a3d.zip.gpg
Plugins que cifran o permiten integración segura
- UpdraftPlus Premium: permite cifrado y subida a S3, pCloud, FTP con clave.
- BlogVault: backups encriptados y gestionados desde su propia plataforma.
- WPvivid Backup Pro: cifrado AES y subida a nubes.
Auditoría y alertas
- Usa inotify o Monit para detectar nuevos archivos
.sql,.zip,.gzen tu servidor. - Integra logs con n8n para que te notifique por Telegram o similar cuando haya nuevas copias.
- Verifica regularmente que puedes desencriptar los backups.
Un backup mal protegido es como dejar una caja fuerte abierta en la calle: contiene todo lo que un atacante necesita para comprometer tu sitio.
Backups guardados en el servidor de producción
Es tentador dejar las copias de seguridad en el mismo servidor por comodidad o por falta de automatización, pero esta práctica representa un riesgo crítico para la seguridad y la disponibilidad de tu proyecto WordPress.
Por qué es un error grave:
- Si el servidor es comprometido, también lo será el backup.
- En caso de infección por malware, ransomware o hackeo, el atacante puede eliminar o manipular las copias.
- Si hay un fallo en disco o pérdida total del servidor, no tendrás forma de recuperar el sitio.
Ejemplos de malas prácticas comunes:
- Hacer un backup diario y dejarlo en
/home/usuario/backupssin sincronizarlo fuera. - Usar un plugin de backups que guarda los ZIP en
/wp-content/backups/sin eliminar los antiguos. - Automatizar un
mysqldumpque guarda en la misma máquina sin subirlo a la nube.
Qué deberías hacer en su lugar
1. Subir los backups a almacenamiento remoto
- pCloud: con carpeta cifrada y cliente rclone.
- Google Drive o Dropbox: mediante integración con plugins o scripts con rclone.
- Amazon S3 / Backblaze B2: con políticas de retención y cifrado.
- NAS externo: montado por SSH o WebDAV.
2. Automatizar la subida y el borrado local
# Subida con rclone y borrado localrclone copy /home/usuario/backups remote:pcloud/backups/rm /home/usuario/backups/*.zip
Puedes usar cron para automatizarlo:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
3. Mantener múltiples puntos de recuperación
- No dependas de una sola copia.
- Mantén 3 copias en 2 ubicaciones distintas, al menos una fuera del servidor (regla 3-2-1).
Plugins que lo permiten
- UpdraftPlus Premium: subida automática a múltiples destinos.
- Jetpack VaultPress Backup: copias gestionadas fuera del servidor.
- WPvivid: integración con Google Drive, FTP, S3…
Auditoría y control
- Verifica que las copias están completas y accesibles desde fuera del servidor.
- Simula restauraciones cada cierto tiempo.
- Usa logs y notificaciones para confirmar que la copia y la subida se realizaron.
Tener backups es esencial, pero tenerlos mal guardados es casi como no tenerlos. Asegúrate de que tus copias no desaparezcan junto con tu servidor.
Logs no protegidos
Los logs (registros de actividad) son una de las mejores fuentes de información para detectar ataques, errores, cambios sospechosos o mal uso del sistema. Pero si no se protegen adecuadamente, también pueden ser una fuente de fuga de información crítica.

Qué logs suelen generarse en un entorno WordPress:
- Apache / Nginx access.log: peticiones completas al servidor.
- error.log: errores de PHP, avisos del sistema.
- wp-content/debug.log si tienes
WP_DEBUG_LOGactivado. - Logs de plugins de seguridad (Wordfence, iThemes, WP Cerber…).
- Logs del sistema (
/var/log/auth.log,/var/log/mysql.log, etc.).
Qué información sensible pueden contener:
- IPs, user-agents, cookies, tokens, URLs completas.
- Claves API que pasan por GET o POST.
- Errores con trazas que revelan rutas internas o configuraciones.
- Fallos de login con nombre de usuario reales.
Riesgos habituales:
- Dejar logs accesibles desde la web (
/wp-content/debug.logpúblico). - Guardar logs indefinidamente sin rotación (riesgo de llenado de disco).
- Permitir que los plugins creen logs sin control.
Buenas prácticas de seguridad con logs
1. No permitir acceso web a debug.log u otros logs en el frontend
Apache (.htaccess)
<Files "debug.log"> Order allow,deny Deny from all</Files>
Nginx
location ~* /debug.log$ { deny all; return 403;}
2. Rotar y limpiar los logs
- Usa herramientas como logrotate en Linux para mantener logs por 7, 14 o 30 días.
- No dejes logs infinitamente si no los estás usando.
3. Revisar y auditar los logs regularmente
- Usa
grep,zgrep,lesso herramientas como GoAccess o Fail2ban. - Busca patrones como:
grep "login" /var/log/nginx/access.log
4. No registrar información sensible innecesaria
- Asegúrate de que los plugins no escriben tokens, contraseñas o información sensible.
- Evita que los usuarios puedan activar
WP_DEBUG_LOGdesde el frontend sin control.
Plugins de ayuda
- WP Activity Log: para ver logs desde el admin.
- WP Debugging: activa log solo para admins.
Los logs bien gestionados son una herramienta poderosa para proteger WordPress. Pero mal configurados, son una mina de oro para atacantes.
Dar acceso a terceras personas
En muchos proyectos WordPress colaborativos es común otorgar acceso a terceros: diseñadores, desarrolladores externos, agencias o incluso el propio cliente. El problema surge cuando este acceso no está bien gestionado, auditado o se mantiene más tiempo del necesario.

Qué puede pasar si no se controla el acceso:
- Un usuario antiguo con permisos de administrador puede seguir haciendo cambios o instalar malware.
- Un diseñador deja las credenciales guardadas en su navegador o en su gestor de contraseñas.
- Se comparten contraseñas en texto plano por email, WhatsApp o notas compartidas.
- No se auditan las acciones de usuarios con permisos elevados.
Casos reales y frecuentes:
- El cliente da acceso a otro proveedor sin informar.
- Se olvida eliminar a un freelance tras finalizar el trabajo.
- Todos usan el mismo usuario y contraseña para entrar (sin trazabilidad).
Buenas prácticas de control de accesos en WordPress
1. Crear un usuario por persona o perfil
- No uses usuarios genéricos tipo admin, editor1, etc.
- Cada persona debe tener su propia cuenta, incluso si es temporal.
2. Asignar el rol mínimo necesario
- Usa Editor si no necesita acceder a plugins o ajustes.
- Usa Shop Manager en WooCommerce si solo gestiona pedidos.
- Evita dar Administrador salvo que sea estrictamente necesario.
3. Eliminar o desactivar accesos temporales
- Usa plugins como Temporary Login Without Password.
- O desactiva usuarios con
wp user updatevía WP-CLI:
wp user update 123 --role=none
4. Usar plugins de gestión de accesos y auditoría
- WP Activity Log: registra cambios, logins, modificaciones de contenido.
- Members: para crear roles personalizados.
- User Switching: útil para debug sin compartir claves.
5. Nunca compartas credenciales por canales inseguros
- Usa gestores de contraseñas con uso compartido como Bitwarden, 1Password o ProtonPass.
- Si usas 2FA, activa notificaciones y confirma dispositivos confiables.
Auditoría y control periódico
Compartir acceso no es un problema, lo es hacerlo sin control. Un solo acceso desatendido puede ser la puerta de entrada a todo tu sitio.
Por eso conviene:
- Revisar cada trimestre qué usuarios existen, su rol y su última actividad
- Eliminar o bloquear los que no sean necesarios
- Documentar quién tiene acceso y con qué finalidad
Un hosting a prueba de todo
Olvídate de caídas y carga lenta. Tu web, siempre rápida, segura y disponible.
Ignorar avisos de seguridad
Muchos servidores modernos cuentan con herramientas de análisis automático que pueden detectar archivos sospechosos, accesos anómalos o software malicioso. Pero de nada sirve si esos avisos se ignoran o no se revisan periódicamente.
Tipos de herramientas de escaneo habituales:
- ClamAV: antivirus gratuito muy usado en entornos Linux.
- Maldet (Linux Malware Detect): escáner de malware para servidores web.
- ImunifyAV/Imunify360: integrado en muchos paneles como cPanel.
- Monit + scripts personalizados: permiten detectar archivos nuevos o sospechosos.
- Plugins como Wordfence, Sucuri o iThemes Security: escanean el sitio desde dentro de WordPress.
Qué problemas puedes estar ignorando sin saberlo:
- Archivos PHP maliciosos en
wp-content/uploads. - Backdoors en plugins obsoletos o crackeados.
- Inyecciones en archivos
.htaccess,wp-config.php, etc. - Accesos desde países no habituales o desde IPs en listas negras.
Errores comunes:
- Dejar los avisos en la bandeja del sistema o correo sin leer.
- No revisar el panel del proveedor (ej: GridPane, cPanel) con informes de seguridad.
- Pensar que es un «falso positivo» sin investigarlo.
Buenas prácticas ante avisos de seguridad
1. Configura alertas visibles y accionables
- Redirige los avisos a un correo operativo (no a uno que nunca se revisa).
- Usa Telegram, Slack o Discord con bots que notifiquen escaneos.
2. Integra en tu flujo de trabajo
- Añade una revisión semanal de logs y escaneos en tu checklist.
- Documenta cada alerta y cómo se resolvió.
3. Automatiza acciones si el nivel es crítico
- Si ClamAV detecta malware, mueve el archivo a cuarentena automáticamente.
- Si un plugin sospechoso se instala, bloquea el acceso con firewall (CSF, Fail2ban, etc.).
4. No ignores alertas de WordPress
- Wordfence, Sucuri, etc. deben tener notificaciones activas.
- Revisa desde el panel los cambios detectados: archivos, plugins, redirecciones.
5. Evalúa si son falsos positivos, pero no asumas que lo son
- Compara hash del archivo con una versión limpia.
- Usa VirusTotal para analizar archivos individuales.
- Revisa manualmente el código sospechoso si es posible.
Herramientas útiles:
- clamscan, maldet, chkrootkit desde terminal.
- Dashboard de GridPane o paneles como cPanel / Plesk.
- Notificaciones por correo con Mailgun, SendGrid, etc.
- Bots para Telegram con n8n o UptimeKuma.
Ignorar las alertas de seguridad es como tener una alarma en casa que suena y decidir no mirar. Aunque algunas sean rutinarias, otras pueden marcar la diferencia entre prevenir un hackeo o descubrirlo demasiado tarde.
Checklist de seguridad en WordPress
A continuación te dejamos una lista de comprobación práctica con los 32 errores del artículo, incluyendo cómo detectarlos y soluciones rápidas para cada uno:
Podrás usarla como guía para realizar una auditoría rápida o descargarla e imprimirla para revisar cualquier proyecto WordPress nuevo o existente.
Cómo usar la checklist
- Revisa cada punto cuando audites una nueva instalación.
- Marca acciones con ✅, ⚠️ o ❌ según el estado.
- Programa revisiones trimestrales de seguridad con base en esta lista.
Con esta checklist cierras el ciclo completo: desde entender los errores hasta detectarlos y prevenirlos. Puedes integrarla en tu flujo de trabajo o compartirla con tus clientes como parte del mantenimiento profesional de sus webs WordPress.
No utilices los comentarios para hacer preguntas, solicitar ayuda o informar de errores. Para ello ponemos a tu disposición nuestros foros o el formulario de contacto con el servicio de soporte.
Antes de publicar un comentario, lee nuestras normas sobre comentarios.