Seguridad en plugins de WordPress: la checklist de 12 puntos que todo plugin debería cumplir
Checklist práctica de 12 puntos de seguridad para plugins de WordPress: nonces, capability checks, saneo, escape, queries preparadas, acceso seguro a ficheros, REST y más.
Un plugin de WordPress vive en el mismo proceso PHP que el resto de la web. Si tiene un fallo de seguridad, toda la web tiene un fallo de seguridad. Aquí va la checklist de 12 puntos que todo plugin debería cumplir antes de entrar en una instalación de WordPress en producción. Imprímela. Pégala junto al monitor.
1. Nonces en cada formulario y endpoint AJAX
Usa wp_nonce_field() en formularios y check_admin_referer() o check_ajax_referer() en el receptor. Sin nonces, tu plugin es vulnerable a CSRF: una web maliciosa puede disparar acciones de admin en tu dashboard mientras estás logueada.
2. Capability checks en toda acción privilegiada
Usa current_user_can() con la capability adecuada antes de cualquier acción que modifique datos. "Estar logueado" no es lo mismo que "estar autorizado". Un suscriptor no debería poder llamar a un endpoint que crea posts.
3. Sanea cada entrada
Usa sanitize_text_field(), sanitize_email(), absint(), sanitize_key() o wp_kses() según el tipo esperado. Nunca confíes directamente en $_POST, $_GET o $_REQUEST.
4. Escapa cada salida
Usa esc_html(), esc_attr(), esc_url(), esc_js() en el punto de salida, no en el de almacenaje. La función de escape depende del contexto: esc_attr para atributos HTML, esc_url para URLs en href/src, esc_html para contenido visible.
5. SQL solo con prepared statements
Usa siempre $wpdb->prepare() para cualquier query con input de usuario. Nunca concatenes variables en strings SQL, aunque "confíes" en la fuente. La inyección SQL es la causa más común de takeover total de WordPress.
6. Acceso directo a ficheros bloqueado
Cada fichero PHP del plugin debería empezar con if (!defined('ABSPATH')) exit;. Esto evita que alguien ejecute el fichero directamente vía /wp-content/plugins/tu-plugin/algun-fichero.php saltándose la autenticación de WordPress.
7. Subidas de fichero validadas por contenido, no por nombre
Usa wp_check_filetype_and_ext() con verificación correcta de MIME. Comprobar solo la extensión deja que un atacante suba shell.php.jpg y lo ejecute.
8. Sin input de usuario en rutas de fichero
Nunca concatenes input de usuario en file_get_contents(), require o include. El path traversal (../../wp-config.php) es un vector de ataque real. Si tienes que aceptar un nombre de fichero del usuario, valida que esté en una whitelist.
9. Almacenamiento seguro de secretos
Las API keys de servicios externos no deberían guardarse en get_option() en texto plano. Usa las constantes de wp-config.php, o como mínimo un wrapper que las codifique en base64 con sal específica del sitio. Mejor aún, usa los patrones de vault de secretos introducidos en WordPress 6.5.
10. Eventos cron desprogramados al desactivar
Si tu plugin programa eventos con wp_schedule_event(), debe llamar a wp_clear_scheduled_hook() en su hook de desactivación. Si no, el evento cron sigue disparándose contra un plugin desactivado, lo que produce errores o, peor, sigue haciendo lo que estuviera haciendo si la función todavía existe.
11. Uninstall.php limpia todo
Tablas custom, opciones, transients, capabilities, eventos programados. El plugin debe dejar la BD en el mismo estado que antes de la instalación cuando se desinstala. Plugins que dejan basura son responsabilidad de mantenimiento y exposición de seguridad (las opciones viejas a veces contienen credenciales caducadas).
12. Permission callbacks en la REST API
Cada llamada a register_rest_route() debe incluir permission_callback. Devolver '__return_true' aquí equivale a dejar la puerta abierta al público — y eso es exactamente sobre lo que iban la mayoría de avisos de seguridad de WordPress en 2025.
La regla 13, no escrita
Probar en una instalación real de WordPress con WP_DEBUG activado antes de publicar. La mitad de los problemas de seguridad de plugins se cazan simplemente ejecutándolos con debug logging durante una hora. La otra mitad se cazan siguiendo esta checklist.
Cómo IC pluginswp valida esto por ti
Cada plugin generado por IC pluginswp pasa esta lista de 12 puntos como parte de su validación automática. Además se activa en una sandbox real de WordPress 6.8 antes de entregártelo, con WP_DEBUG_LOG activo, así que cualquier fatal se detecta y se repara antes de que lo recibas. Nada de esto sustituye tu propia revisión en una web de mucho tráfico, pero es el tipo de baseline que de otro modo tendrías que imponer manualmente en cada contrato con freelance.