Une vulnérabilité critique est publiée, l'avis de sécurité circule et, en moins d'une heure, quelqu'un demande sur la messagerie de l'entreprise : sommes-nous concernés ? Log4Shell a rendu la question célèbre. CVE-2021-44228 touchait Log4j Core de la version 2.0-beta9 à la version 2.15.0, une bibliothèque nichée plusieurs niveaux plus bas dans l'arbre de dépendances d'innombrables produits Java, et la plupart des équipes ont dû découvrir à leurs dépens où elle se trouvait.
La question paraît simple. En réalité, elle en contient trois :
- Le composant vulnérable se trouve-t-il dans ce que nous construisons ou livrons ?
- Si oui, peut-il être exploité dans notre produit ?
- Depuis quand, et dans quelles releases ?
La plupart des processus répondent aux deux premières. La troisième est celle que posent ensuite les clients, les auditeurs et les régulateurs, et c'est la plus difficile à traiter après coup.
Étape 1 : déterminer si le composant est présent
Les entreprises arrivent généralement à une réponse de l'une de ces quatre façons, à peu près par ordre de maturité.
Demander autour de soi et chercher. Quelqu'un poste un message sur Slack, les ingénieurs cherchent le nom du paquet dans leurs dépôts et leurs lockfiles, et un tableur recueille les réponses. C'est encore la méthode la plus courante. Elle est lente, dépend de ceux qui répondent et passe à côté de tout ce qui n'est pas déclaré dans un fichier : les dépendances des dépendances, les bibliothèques vendorisées, les images de base, les outils installés pendant le build.
Consulter les tableaux de bord des scanners. Les scanners de dépendances signalent la CVE par dépôt en quelques heures. C'est plus rapide, mais un scanner rend compte du code qu'il a devant lui aujourd'hui, en général la branche par défaut. Il ne vous dit pas quelles releases vos clients exécutent, ni ce qu'un build a réellement récupéré il y a trois mois.
Interroger un inventaire de SBOM. Les équipes qui conservent une nomenclature logicielle pour chaque release peuvent poser une seule question sur l'ensemble : quels produits et quelles versions contiennent les versions affectées de ce paquet ? C'est la première méthode qui répond pour les logiciels que vous avez livrés, et pas seulement pour ceux qui sont dans le dépôt.
Comparer en continu. Quand les SBOM sont surveillées au regard des données de vulnérabilités, la liste des produits affectés existe avant que quiconque ne la demande. La discussion commence par la réponse et non par la question.
La qualité de chaque méthode dépend de ce que contient réellement l'inventaire. Les angles morts habituels sont les suivants :
- Les dépendances transitives. Le paquet vulnérable est rarement un paquet que vous avez ajouté vous-même. Il arrive trois ou quatre niveaux plus bas.
- Tout ce que le manifeste ne déclare pas. Les paquets installés par des scripts de build, les outils
npx, les étapes de Dockerfile, les caches restaurés et le code C et C++ vendorisé. - Les anciennes releases. Une branche qui ne se construit plus ne peut pas être scannée à nouveau, mais le produit qui en est issu peut encore être en service.
Étape 2 : décider si cela compte
Un composant peut être présent sans représenter un risque réel. L'étape suivante est donc le tri :
- Version et configuration. La version se situe-t-elle exactement dans la plage affectée ? La fonction vulnérable est-elle compilée et activée ?
- Atteignabilité. Votre code appelle-t-il seulement la fonction vulnérable ?
- Exposition. Le composant est-il accessible depuis le réseau ou depuis des entrées non fiables, ou utilisé uniquement au moment du build ?
- Mesures d'atténuation. Existe-t-il un sandboxing, une restriction réseau ou une configuration qui bloque l'exploit ?
- Signaux d'exploitation. CVSS donne la sévérité, EPSS estime la probabilité qu'une CVE soit exploitée dans les 30 prochains jours, et le catalogue Known Exploited Vulnerabilities de la CISA liste celles qui sont déjà exploitées dans la nature. Ensemble, ils décident de ce qui est examiné en premier.
Étape 3 : consigner la décision
Le résultat est consigné par produit et par version, de plus en plus sous forme de déclaration VEX (Vulnerability Exploitability eXchange). Les exigences minimales de la CISA pour VEX définissent quatre statuts : not affected, affected, fixed et under investigation. Une déclaration « not affected » doit en donner la raison, par exemple parce que le code vulnérable n'est pas présent ou qu'un attaquant ne peut pas l'atteindre.
Cet enregistrement alimente tout ce qui suit : le correctif et les releases qui le contiennent, l'avis de sécurité destiné aux clients et tout rapport attendu par un régulateur. Au titre du Cyber Resilience Act de l'UE, par exemple, un fabricant doit envoyer une alerte précoce concernant une vulnérabilité activement exploitée dans son produit dans les 24 heures suivant sa prise de connaissance.
Étape 4 : calculer la fenêtre d'exposition
« Sommes-nous concernés ? » a une seconde moitié souvent oubliée : pendant combien de temps l'avons-nous été ?
La vulnérabilité existait bien avant la publication de la CVE. Log4Shell se trouvait dans Log4j depuis la version 2.0-beta9, publiée des années avant que quiconque ne la divulgue. Votre exposition a commencé le jour où un build a récupéré pour la première fois une version vulnérable, et elle s'est terminée le jour où le dernier build qui la contenait a été remplacé. Vous avez besoin de cette fenêtre pour :
- indiquer aux clients lesquelles des releases qu'ils exécutent sont affectées, et pas seulement la dernière
- limiter une enquête sur incident à la bonne période, si la vulnérabilité a pu être exploitée
- montrer à un auditeur ou à un régulateur quand le problème est entré dans le produit et quand le correctif a été livré
Scanner le code d'aujourd'hui ne peut pas vous donner cela. Le lockfile actuel indique ce que le dépôt demande maintenant, pas ce que chaque build passé a installé. La seule source fiable est une trace de chaque build, prise pendant son exécution et conservée ensuite.
Comment CRACI y répond
CRACI exécute vos jobs GitHub Actions sur ses propres runners et enregistre chaque paquet que chaque build récupère réellement, direct ou transitif, y compris les paquets installés par des scripts et restaurés depuis des caches. La SBOM de chaque build est conservée : l'historique existe donc déjà quand une CVE est publiée.
Quand une nouvelle CVE arrive, la réponse est déjà là : chaque build passé et sa SBOM, ceux qui contenaient la dépendance vulnérable, directe ou transitive, et la période pendant laquelle vous étiez concerné. Pas de tableur, pas de nouveau scan, pas de reconstitution à partir des lockfiles. Le premier build qui la contenait et le build qui l'a retirée vous donnent la fenêtre d'exposition, aussi loin que remonte votre conservation (180 jours par défaut, conservation personnalisée avec Enterprise).
Une fois que vous savez, un policy gate peut bloquer les builds qui contiennent cette CVE, afin qu'une mise à jour de dépendance ultérieure ou un cache restauré ne puisse pas réintroduire discrètement la version vulnérable dans une release.
À partir de là, le reste du processus a une base solide :
- CRACI surveille les SBOM en continu : les nouvelles CVE sont comparées à vos builds sans que personne n'ait à le demander.
- Les équipes sécurité trient les résultats et les transmettent aux équipes chargées de la correction, et CRACI prend en charge VEX pour consigner la décision.
- L'inventaire de CRACI montre quelles versions logicielles sont déployées sur quels produits.
- Pour le CRA, CRACI soumet en votre nom l'alerte précoce, la notification et le rapport final.
Réservez une démo pour voir l'historique des builds de l'un de vos propres dépôts.
