Se publica una vulnerabilidad crítica, el aviso se difunde y, en menos de una hora, alguien pregunta en el chat de la empresa: ¿estamos afectados? Log4Shell hizo famosa la pregunta. CVE-2021-44228 afectaba a Log4j Core desde la 2.0-beta9 hasta la 2.15.0, una biblioteca situada varias capas por debajo en el árbol de dependencias de incontables productos Java, y la mayoría de los equipos tuvieron que averiguar a las malas dónde estaba.

La pregunta parece sencilla. En realidad son tres preguntas:

  1. ¿Está el componente vulnerable en algo que construimos o distribuimos?
  2. Si lo está, ¿se puede explotar en nuestro producto?
  3. ¿Desde cuándo y en qué versiones?

La mayoría de los procesos responden a las dos primeras. La tercera es la que preguntan a continuación los clientes, los auditores y los reguladores, y es la más difícil de responder a posteriori.

Paso 1: averigüe si el componente está ahí

Las empresas suelen llegar a una respuesta de una de estas cuatro formas, más o menos por orden de madurez.

Preguntar y buscar. Alguien escribe en Slack, los ingenieros buscan el nombre del paquete en sus repositorios y lockfiles, y una hoja de cálculo recoge las respuestas. Sigue siendo el método más habitual. Es lento, depende de quién responda y se le escapa todo lo que no esté declarado en un archivo: dependencias de dependencias, bibliotecas incluidas en el repositorio, imágenes base, herramientas instaladas durante el build.

Consultar los paneles de los escáneres. Los escáneres de dependencias señalan la CVE por repositorio en cuestión de horas. Es más rápido, pero un escáner informa sobre el código que tiene delante hoy, normalmente la rama por defecto. No le dice qué versiones ejecutan sus clientes ni qué descargó realmente un build hace tres meses.

Consultar un inventario de SBOM. Los equipos que conservan una lista de materiales de software de cada versión pueden hacer una sola pregunta sobre todas ellas: ¿qué productos y versiones contienen las versiones afectadas de este paquete? Es el primer método que responde por el software que ha distribuido, no solo por el que está en el repositorio.

Cotejar de forma continua. Cuando las SBOM se monitorizan frente a los datos de vulnerabilidades, la lista de productos afectados existe antes de que nadie pregunte. El hilo del chat empieza con la respuesta en lugar de con la pregunta.

La calidad de cada método depende de lo que contenga realmente el inventario. Los puntos ciegos habituales son:

  • Dependencias transitivas. El paquete vulnerable rara vez es uno que haya añadido usted. Llega tres o cuatro niveles más abajo.
  • Todo lo que el manifiesto no declara. Paquetes instalados por scripts de build, herramientas npx, pasos de Dockerfile, cachés restauradas y código C y C++ incluido en el repositorio.
  • Versiones antiguas. Una rama que ya no compila no se puede volver a escanear, pero el producto construido a partir de ella puede seguir en uso.

Paso 2: decida si importa

Un componente puede estar presente sin suponer un riesgo real, así que el siguiente paso es el triaje:

  • Versión y configuración. ¿La versión entra exactamente en el rango afectado? ¿La función vulnerable está compilada y activada?
  • Alcanzabilidad. ¿Su código llama realmente a la función vulnerable?
  • Exposición. ¿Se puede llegar al componente desde la red o desde entradas no fiables, o solo se usa durante el build?
  • Mitigaciones. ¿Hay sandboxing, una restricción de red o una configuración que bloquee el exploit?
  • Señales de explotación. CVSS indica la gravedad, EPSS estima la probabilidad de que una CVE se explote en los próximos 30 días, y el catálogo Known Exploited Vulnerabilities de CISA enumera las que ya se están explotando en la práctica. Juntos deciden qué se examina primero.

Paso 3: registre la decisión

El resultado se registra por producto y versión, cada vez más como una declaración VEX (Vulnerability Exploitability eXchange). Los requisitos mínimos de VEX de CISA definen cuatro estados: no afectado, afectado, corregido y en investigación. Una declaración «no afectado» tiene que indicar el motivo, por ejemplo que el código vulnerable no está presente o que un atacante no puede llegar a él.

Ese registro alimenta todo lo que viene después: la corrección y las versiones que la incluyen, el aviso de seguridad para los clientes y cualquier notificación que espere un regulador. Con el Cyber Resilience Act de la UE, por ejemplo, un fabricante debe enviar una alerta temprana sobre una vulnerabilidad explotada activamente en su producto en un plazo de 24 horas desde que tiene conocimiento de ella.

Paso 4: calcule la ventana de exposición

«¿Estamos afectados?» tiene una segunda parte que a menudo se omite: ¿durante cuánto tiempo lo estuvimos?

La vulnerabilidad existía mucho antes de que se publicara la CVE. Log4Shell llevaba en Log4j desde la 2.0-beta9, publicada años antes de que nadie la revelara. Su exposición empezó el día en que un build descargó por primera vez una versión vulnerable, y terminó el día en que se sustituyó el último build que la contenía. Necesita esa ventana para:

  • decir a los clientes cuáles de las versiones que ejecutan están afectadas, no solo la última
  • acotar al periodo correcto la investigación de un incidente, si la vulnerabilidad pudo explotarse
  • mostrar a un auditor o a un regulador cuándo entró el problema en el producto y cuándo se distribuyó la corrección

Escanear el código actual no puede darle eso. El lockfile actual dice lo que el repositorio quiere ahora, no lo que instaló cada build anterior. La única fuente fiable es un registro de cada build, tomado mientras se ejecutó y conservado después.

Cómo la responde CRACI

CRACI ejecuta sus jobs de GitHub Actions en sus propios runners y registra todos los paquetes que cada build descarga realmente, directos y transitivos, incluidos los paquetes instalados por scripts y restaurados desde cachés. La SBOM de cada build se conserva, de modo que el historial ya está ahí cuando se publica una CVE.

Cuando llega una CVE nueva, la respuesta ya está ahí: todos los builds anteriores y sus SBOM, cuáles de ellos contenían la dependencia vulnerable, directa o transitiva, y el periodo en que estuvo afectado. Sin hojas de cálculo, sin volver a escanear, sin reconstruir nada a partir de lockfiles. El primer build que la contenía y el build que la eliminó le dan la ventana de exposición, hasta donde llegue su retención (180 días por defecto, retención personalizada en Enterprise).

Una vez que lo sabe, un control de política puede bloquear los builds que contengan esa CVE, de modo que una actualización posterior de dependencias o una caché restaurada no puedan volver a colar la versión vulnerable en un lanzamiento.

A partir de ahí, el resto del proceso tiene una base en la que apoyarse:

  • CRACI monitoriza las SBOM de forma continua, de modo que las CVE nuevas se cotejan con sus builds sin que nadie lo pida.
  • Los equipos de seguridad hacen el triaje de los hallazgos y los envían a los equipos responsables de la corrección, y CRACI es compatible con VEX para registrar el resultado.
  • El inventario de CRACI muestra qué versiones de software están desplegadas en qué productos.
  • Para el CRA, CRACI presenta en su nombre la alerta temprana, la notificación y el informe final.

Reserve una demo para ver el historial de builds de uno de sus propios repositorios.