El Ecosystem Security Team de la PHP Foundation publicó el 19 de agosto de 2026 una guía práctica de Sebastian Bergmann que acompaña a los mantenedores de proyectos PHP durante todo el ciclo de vida de un informe de vulnerabilidad. Son diez secciones más una chuleta de una pantalla; se salta directamente a la fase en la que uno se encuentra.

El principio central es la divulgación coordinada: los detalles permanecen privados hasta que exista un parche. Nada de issues públicos, nada de pull requests públicas, nada de mensajes de commit como "fix SQL injection in login handler" y nada de parches en ramas públicas. Un commit así ya es la divulgación. Al mismo tiempo hay que acusar recibo del informe en pocos días, aunque sea con una frase, porque el silencio convierte a los informantes bienintencionados en frustrados que acaban publicando por su cuenta. Un informe es una afirmación, no un veredicto: el mantenedor decide qué es válido, qué está fuera de alcance y cuál es el calendario. "Works as designed" es una respuesta legítima si el informe presupone capacidades que el modelo de seguridad documentado considera confiables.

Una sección entera existe por el peor escenario posible: nunca ejecutar una prueba de concepto en la propia máquina. Allí residen las claves SSH y GPG, las credenciales de Packagist y GitHub y el gestor de contraseñas; un PoC malicioso lo convierte en un ataque a la cadena de suministro contra todos los que instalan el paquete. La jerarquía de aislamiento: un sandbox microVM como Docker Sandboxes (sbx), con su propio kernel y red bloqueada por defecto; un contenedor, teniendo en cuenta que en Linux los contenedores comparten el kernel del anfitrión mientras que Docker Desktop en macOS y Windows ya está detrás de una frontera de VM; una VM endurecida con snapshot y sin carpetas compartidas; o una VM desechable en la nube. Los archivos de entrada manipulados como archivos .phar o payloads serializados cuentan como código y siguen las mismas reglas.

El parche se prepara en el fork privado temporal de las GitHub Security Advisories, primero la prueba de regresión y con mensajes de commit neutros. Trampas: la CI no corre en forks privados, el fork no sobrevive a la advisory, y un parche silencioso sin advisory deja ciegos a composer audit y Dependabot. La guía también aconseja barrer en busca de errores hermanos de la misma clase antes de publicar, porque una advisory pone el foco sobre esa clase de debilidad, y decidir si las ramas antiguas mantenidas necesitan backports.

Para los paquetes Composer, tres campos de la advisory deciden si la maquinaria funciona: el ecosistema debe ser Composer, el nombre del paquete debe ser exactamente el nombre de Packagist en formato vendor/package, y los rangos de versiones afectadas deben ser restricciones Composer precisas. Esto importa más que antes porque desde Composer 2.9 el resolvedor de dependencias elimina activamente las versiones cubiertas por advisories del pool de candidatos; Composer 2.10 lo generalizó en un marco unificado de política de dependencias que también bloquea paquetes marcados como malware incluso durante un composer install. Los rangos demasiado amplios causan daños reales: en una advisory de PHPUnit de abril de 2026, GitHub reescribió las versiones afectadas concretas 12.5.21 y 13.1.5 en rangos amplios, haciendo que de la noche a la mañana todas las versiones antiguas de PHPUnit dejaran de ser instalables, incluida PHPUnit 11, que nunca estuvo afectada. La corrección más rápida pasa por una pull request a FriendsOfPHP/security-advisories, cuyos datos tienen prioridad en Packagist, más una PR a la GitHub Advisory Database.

El día de la publicación sigue un orden fijo: fusionar el parche, etiquetar y publicar la release, confirmar que aparece en Packagist, publicar la advisory, enviar la pull request a FriendsOfPHP y luego anunciar. El paso de FriendsOfPHP no debe saltarse: Composer no lee las advisories a nivel de repositorio, y la revisión de GitHub hacia la Advisory Database se retrasa días o semanas. Para proyectos alojados fuera de GitHub es la única vía de entrada a las herramientas. La brecha entre release y advisory debe ser de minutos u horas, no de días. Si los detalles se filtran antes, el embargo ha terminado de facto y se publica lo que se tenga.

Sobre los CVE: GitHub es una CNA y se puede solicitar un identificador CVE desde la advisory, pero las solicitudes tardan actualmente semanas. Lo que realmente protege a los usuarios es la GHSA, porque sobre ella actúan Composer, composer audit y Dependabot. Por tanto, nunca hay que retrasar una release esperando un CVE. Dar crédito al informante en la advisory no cuesta nada y es gran parte de lo que hace que el reporte responsable merezca la pena.

Las secciones finales tratan la postura a largo plazo: activar GitHub Private Vulnerability Reporting y añadir un SECURITY.md; exigir 2FA robusto en GitHub, Packagist y el correo, con Packagist dispuesto a mostrar públicamente el estado MFA de los mantenedores; nunca reetiquetar una versión publicada, algo que Packagist ya rechaza para versiones estables; borrar ramas y workflows obsoletos para reducir el riesgo de Poisoned Pipeline Execution; y endurecer los workflows de GitHub Actions, donde los de PHPUnit pasaron de 52 hallazgos a cero tras corregir inyección de plantillas, persistencia de credenciales, acciones sin fijar, permisos demasiado amplios y acciones de terceros innecesarias, con zizmor recomendado como comprobación automatizada.

Los mantenedores atascados pueden contactar con el Ecosystem Security Team en volker@thephp.foundation o en el canal #ecosystem-security del Discord de phpc. El equipo ayuda con triaje, reproducción en entornos aislados, puntuación de severidad y divulgación coordinada, y afirma explícitamente que no quiere interponerse entre un informe y su parche.