Situación actual: PHP2Shell. Dos vulnerabilidades críticas de PHP (CVSS 9.2) permiten ejecutar código malicioso sin autenticación. Parches desde el 21/10/2026.Qué hacer ahora →

Análisis estático: PHPStan y Psalm

PHPStan y Psalm encuentran errores en el código PHP sin ejecutarlo. Psalm sigue además los flujos de datos inseguros. Ninguno de los dos halla vulnerabilidades del propio intérprete de PHP.

Actualizado 5 min de lecturaConocimiento de PHP

En resumen: el análisis estático revisa el código PHP sin ejecutarlo y encuentra así errores de tipo, variables sin definir, código muerto y llamadas sobre valores posiblemente vacíos. Las dos herramientas más extendidas son PHPStan (niveles de reglas 0 a 10) y Psalm (niveles de error 1 a 8, además de un análisis de taint para flujos de datos inseguros). Encuentran errores en su aplicación, no en el intérprete de PHP; frente a vulnerabilidades como PHP2Shell solo ayuda la actualización de PHP.

¿Qué es el análisis estático?

Una prueba ejecuta el código y compara el resultado. El análisis estático, en cambio, lee el código como un revisor muy minucioso y deduce a partir de los tipos, los valores devueltos y las llamadas dónde puede salir algo mal. Encuentra errores también en ramas que ninguna prueba alcanza nunca.

Para quienes toman decisiones, el beneficio es sencillo: los fallos que se encuentran antes de la puesta en producción cuestan una fracción de los que notan los clientes. Para los desarrolladores es un acompañante constante que se ejecuta en el entorno de desarrollo y en la canalización de CI. Si el análisis salta ante un cambio, este no se integra hasta que se corrija el fallo. Así no se acumula una herencia nueva mientras se reduce poco a poco la existente. Junto con las pruebas con PHPUnit y Pest constituye la base de la calidad del código.

PHPStan: niveles de reglas de 0 a 10

PHPStan se instala como dependencia de desarrollo y necesita PHP 7.4 o superior para funcionar:

composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse src tests

Sin más indicaciones, PHPStan comprueba solo lo imprescindible. La exigencia se controla mediante once niveles, cada uno de los cuales incluye los inferiores:

Nivel Qué se comprueba además (selección)
0 clases y funciones desconocidas, número incorrecto de argumentos, variables siempre sin definir
3 tipos devueltos y tipos que se asignan a propiedades
5 tipos de los argumentos en llamadas a funciones y métodos
6 indicaciones de tipo ausentes
8 llamadas a métodos y accesos a propiedades sobre valores que pueden ser null
10 el tratamiento más estricto de mixed, también con tipos ausentes

Con --level max se ejecuta siempre el nivel más alto. La documentación advierte, sin embargo, de que una actualización de PHPStan puede traer entonces muchos avisos nuevos. Un hallazgo típico desde el nivel 8:

<?php
function kundenname(?Kunde $kunde): string
{
    return $kunde->name();   // PHPStan: llamada sobre un valor que puede ser null
}

Introducir PHPStan sin una avalancha de errores: la baseline

En proyectos con muchos años, PHPStan suele notificar cientos de puntos en un nivel alto. La baseline resuelve el problema: guarda todos los avisos existentes en un archivo y, a partir de ese momento, PHPStan solo notifica los errores nuevos.

vendor/bin/phpstan analyse --level 6 src tests --generate-baseline

El archivo generado phpstan-baseline.neon se incluye en la configuración:

includes:
    - phpstan-baseline.neon

parameters:
    level: 6
    paths:
        - src
        - tests

Así, la herencia acumulada queda documentada de forma visible, mientras que el código nuevo debe estar limpio desde el principio.

Psalm y el análisis de taint

Psalm persigue objetivos similares a los de PHPStan. Los niveles van al revés: 1 es el más estricto, 8 el más indulgente, y el valor por defecto es 2. Psalm necesita PHP 8.2 o superior y se configura así:

composer require --dev vimeo/psalm
./vendor/bin/psalm --init
./vendor/bin/psalm --taint-analysis

El análisis de taint es especialmente interesante para la seguridad. «Taint» significa contaminación: Psalm marca los datos procedentes de fuentes que un atacante puede controlar, como $_GET, $_POST, $_COOKIE, $_REQUEST o php://input. Después sigue si esos datos llegan sin protección a puntos peligrosos, los llamados sumideros: salida con echo, include, header o consultas SQL. Entre las categorías integradas están, entre otras, sql, html, shell, include, eval, ssrf y unserialize.

<?php
// Psalm notifica un flujo de $_GET a la salida HTML (categoría html)
echo 'Hallo ' . $_GET['name'];

// Corregido: escapar la salida según el contexto
echo 'Hallo ' . htmlspecialchars($_GET['name'] ?? '', ENT_QUOTES, 'UTF-8');

La documentación de Psalm reconoce abiertamente los límites: el análisis supone que el escapado se hace correctamente. Fallos sutiles, como unas comillas ausentes alrededor de un atributo HTML, pueden aun así dejar vulnerabilidades. Por eso Psalm recomienda consultas parametrizadas para SQL y plantillas que tengan en cuenta el contexto para HTML. Los resultados pueden emitirse en formato SARIF, que entiende, entre otros, GitHub Code Scanning.

Análisis estático y seguridad tras PHP2Shell

Aquí conviene una delimitación honesta. PHP2Shell, es decir, CVE-2026-109618 y CVE-2026-109619, está en el intérprete de PHP. Ninguna herramienta que lea el código de su aplicación encuentra estas vulnerabilidades, y ningún cambio de código las cierra. Eso solo lo consigue la actualización a PHP 8.5.12, 8.4.27, 8.3.36 o 8.2.35.

Aun así, el análisis estático contribuye a la seguridad en tres puntos:

  1. Capacidad de actualización: encuentra código que ya no funciona en las nuevas versiones de PHP. Así baja la barrera para pasar de 8.1 u 8.2 a una versión con soporte.
  2. Vulnerabilidades propias: el análisis de taint encuentra caminos hacia la inyección SQL, el cross-site scripting o la inclusión de archivos. El proyecto PHP aclara en su política de seguridad que las entradas sin comprobar enviadas a funciones como mysqli_query() no son un fallo de PHP, sino que son responsabilidad de la aplicación.
  3. Robustez: muchos errores fatales surgen de llamadas sobre null o de tipos incorrectos. En relación con CVE-2026-109619, php.net aconseja expresamente corregir en la aplicación los errores fatales que puedan provocarse desde fuera.

El análisis estático no sustituye a una revisión de código de seguridad hecha por personas, pero la hace más eficiente, porque los errores rutinarios ya se han descartado antes.

¿Cómo ayuda PHP SOS en concreto?

En el marco de la auditoría de seguridad y prueba de penetración procedemos así:

  • Configurar las herramientas: PHPStan o Psalm con el nivel adecuado y la baseline, integrados en su canalización existente.
  • Valorar los hallazgos de seguridad: revisamos los resultados del análisis de taint y separamos los riesgos reales de las falsas alarmas.
  • Preparar la actualización: mostramos qué puntos bloquean el cambio a una versión de PHP con soporte.
  • Entregar los resultados: recibirá una lista priorizada con puntos concretos del código para su equipo o su agencia.

Preguntas frecuentes

¿Qué diferencia hay entre PHPStan y Psalm?

Ambos comprueban tipos y encuentran errores sin ejecutar el código. PHPStan cuenta sus niveles de 0 (laxo) a 10 (estricto); Psalm, de 8 (laxo) a 1 (estricto). Psalm incorpora un análisis de taint integrado para problemas de seguridad.

¿Puedo introducir PHPStan en un proyecto antiguo?

Sí. Con una baseline, PHPStan guarda en un archivo todos los avisos existentes y después solo notifica los errores nuevos. Así el equipo empieza sin una avalancha de errores y reduce poco a poco la herencia acumulada.

¿Encuentra el análisis estático PHP2Shell?

No. PHP2Shell está en el intérprete de PHP, no en su código. Contra eso solo ayuda la actualización de PHP. El análisis estático sí ayuda a preparar el código para las nuevas versiones de PHP, de modo que la actualización sea posible con más rapidez.

¿Qué nivel conviene elegir?

Para empezar, un nivel bajo sin baseline o uno más alto con baseline. Más importante que la cifra es que el análisis se ejecute automáticamente con cada cambio y no deje pasar errores nuevos.

Fuentes

Contacto inmediato

Cada hora cuenta. Escríbanos ahora.

Describa brevemente el sistema, la versión de PHP y lo que ha observado. Nos pondremos en contacto, aclararemos la situación y trabajaremos en remoto hasta que el incidente quede cerrado y documentado.

Ayuda inmediata