Analyser les rapports CVE de Yocto avec cve-parse

Publié par cpb
Oct 20 2026

Pour faciliter l’analyse des rapports concernant les CVE produits lors d’un build Yocto Project, j’ai développé un petit outil nommé cve-parse. Il permet d’obtenir rapidement une vue d’ensemble des composants d’une image, de consulter les vulnérabilités associées à un composant particulier ou de rechercher directement une CVE.

Dans le précédent article, consacré au Cyber Resilience Act, nous avons vu qu’en cas de découverte d’une vulnérabilité activement exploitée, l’une des premières questions auxquelles le fabricant doit pouvoir répondre est très simple en apparence : mon produit contient-il le composant vulnérable ?

Dans un système Linux embarqué, la réponse est rarement simple à obtenir. Une image contient plusieurs dizaines ou centaines de composants logiciels, auxquels peuvent être associées des centaines, voire des milliers d’entrées CVE.

Le projet Yocto fournit heureusement les outils nécessaires pour produire une SBOM (Software Bill of Materials, « inventaire logiciel » en français) et analyser les vulnérabilités connues associées aux composants d’une image. Les informations produites sont très complètes. Parfois même un peu trop si l’on veut simplement obtenir un premier aperçu de la situation.

C’est pour faciliter cette exploration que j’ai développé (avec pas mal d’aide de Codex), un petit outil nommé cve-parse. Son code est disponible ici : https://github.com/cpb-/yocto-cve-parser. Il est placé sous licence MIT.

Dans cet article, nous allons construire une image Yocto de test, générer son rapport de vulnérabilités puis voir comment cve-parse permet de l’explorer.

Je suis parfaitement conscient qu’il existe probablement d’autres outils permettant d’analyser les CVE et les rapports de Yocto Project, j’avais simplement envie d’un outil adapté à mon besoin (le suivi du socle logiciel offert par Eris Linux) et c’était l’occasion de m’amuser avec Codex pour le développement et la documentation d’un petit outil Open Source.

Produire un rapport CVE avec Yocto

Pour cet exemple, je vais utiliser Yocto Cooker, afin d’accélérer la mise en place du build. Commençons par créer un environnement Python dédié, et installer Cooker :

$ sudo apt install  python3.12-venv
  [...]

$ python3  -m  venv  cooker-env

$ . cooker-env/bin/activate

$ python3  -m  pip  install  --upgrade  yocto-cooker
  [...]

Récupérons ensuite les menus d’exemple fournis dans le dépôt de Yocto Cooker :

$ git  clone  https://github.com/cpb-/yocto-cooker

$ cp  yocto-cooker/sample-menus/qemu-sample-menu-wrynose.json  .

Nous allons utiliser une cible QEMU Arm, pour produire rapidement une image, mais ce qui nous intéresse ce sont les rapports de vulnérabilités. Je n’ai même pas l’intention de faire démarrer l’image produite.

Les lignes à ajouter dans le fichier conf/local.conf pour produire le rapport de vulnérabilité ont changé depuis la branche Wrynose. 🙄

Avec le menu utilisant la branche Yocto Wrynose, nous ajoutons au fichier local.conf la ligne OE_FRAGMENTS suivante :

"local.conf": [
    "MACHINE = 'qemuarm'                     ",
    "DISTRO  = 'poky'                        ",
    "IMAGE_FEATURES += 'empty-root-password' ",
    "OE_FRAGMENTS += 'core/yocto/sbom-cve-check' "
]

Alors qu’avec une branche antérieure comme Scarthgap, il fallait ajouter la ligne INHERIT :

"local.conf": [
    "MACHINE = 'qemuarm'                     ",
    "DISTRO  = 'poky'                        ",
    "IMAGE_FEATURES += 'empty-root-password' ",
    "INHERIT += 'cve-check'                  "
]

Construction de l’image

Nous pouvons construire l’image avec la commande suivante, qui va prendre un peu de temps et qui produira par la même occasion le rapport de vulnérabilités :

$ cooker  cook  qemu-sample-menu-wrynose.json

  [...]

Initialising tasks: 100% |########################################| Time: 0:00:04
NOTE: Executing Tasks

  [...]

Une fois la compilation terminée, plusieurs nouveaux éléments apparaissent dans le répertoire tmp/ :

$ ls  builds/build-qemuarm/tmp/deploy/

images  licenses  rpm  sbom-cve-check  spdx

Notamment, dans le répertoire images/ :

$ ls  builds/build-qemuarm/tmp/deploy/images/qemuarm
  [...]
core-image-base-qemuarm.rootfs-20261017082851.sbom-cve-check.spdx.json
core-image-base-qemuarm.rootfs-20261017082851.sbom-cve-check.yocto.json
core-image-base-qemuarm.rootfs-20261017082851.spdx.json
  [...]
core-image-base-qemuarm.rootfs.sbom-cve-check.spdx.json
core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json
core-image-base-qemuarm.rootfs.spdx.json

Le fichier qui nous intéresse principalement est core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json. Il contient le rapport produit par Yocto. En jetant un coup d’œil à son contenu nous voyons qu’il est particulièrement détaillé, et sera difficile à consulter tel quel :

{
  "version": "1",
  "package": [
    {
      "name": "acl",
      "layer": "core",
      "version": "2.3.2",
      "products": [
        {
          "product": "acl",
          "cvesInRecord": "Yes"
        }
      ],
      "issue": [
        {
          "id": "CVE-2009-4411",
          "status": "Patched",
          "link": "https://nvd.nist.gov/vuln/detail/CVE-2009-4411",
          "summary": "...",
          "scorev2": "3.7",
          "scorev3": "0.0",
          "scorev4": "0.0",
          "modified": "2026-06-16T23:13:36.000",
          "vector": "LOCAL",
          "vectorString": "AV:L/AC:H/Au:N/C:P/I:P/A:P",
          "detail": "version-not-in-range"
        },

        [...]

Le format est adapté à un traitement automatisé et contient beaucoup d’informations intéressantes : composant, numéro de version, numéro de CVE, présence d’un patch, score CVSS, vecteur d’attaque, description, etc. En revanche, pour un humain il est difficile de savoir quelles vulnérabilités non corrigées sont présentes dans l’image.

On peut évidemment écrire des requêtes jq, mais j’avais envie d’un petit outil spécialisé permettant de naviguer rapidement dans ces informations.

Pour les branches de Yocto antérieures (jusqu’à Scarthgap), le fichier était :

$ ls  builds/build-qemuarm-scarthgap/tmp/deploy/images/qemuarm/
core-image-base-qemuarm.rootfs-20261017161823.cve
  [...]
core-image-base-qemuarm.rootfs.cve
  [...]
$

C’est le lien symbolique core-image-base-qemuarm.rootfs.cve qui nous intéresse. Il contient les vulnérabilités concernant les packages embarqués sur la cible.

À l’inverse, dans le build Wrynose utilisé ici, j’ai constaté que le rapport core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json contient également des composants qui ne sont pas présents dans le système de fichiers final. À titre d’exemple, bash apparaît dans le rapport alors qu’il n’est pas installé sur notre cible.

$ jq  -r  ".package[].name"  core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json  |  grep  'bash'
bash
bash-completion

Il faudra donc filtrer les packages pour ne conserver que ceux qui sont dans le manifeste de la cible. Nous utiliserons le second fichier fourni par Yocto (depuis Wrynose) : core-image-base-qemuarm.rootfs.spdx.json et une option spécifique de cve-parse.

Installation de cve-parse

Récupérons le projet :

$ git  clone  https://github.com/cpb-/yocto-cve-parser

Copions dans notre répertoire de travail les deux fichiers produits par la branche Wrynose :

$ cp  builds/build-qemuarm/tmp/deploy/images/qemuarm/core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json  .

$ cp  builds/build-qemuarm/tmp/deploy/images/qemuarm/core-image-base-qemuarm.rootfs.spdx.json  .

Nous pouvons maintenant commencer l’analyse.

Aperçu de la situation

Sans option supplémentaire et avec uniquement le fichier de CVE, cve-parse affiche un résumé par composant mentionné dans le fichier :

$ ./cve-parse  core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json  
COMPONENT               VERSION       TOTAL  PATCHED  UNPATCHED  IGNORED  OTHER
acl                     2.3.2         4      2        2          0        0
alsa-lib                1.2.15.3      6      2        4          0        0
alsa-state              0.2.0         0      0        0          0        0
alsa-ucm-conf           1.2.15.3      0      0        0          0        0
alsa-utils              1.2.15.2      0      0        0          0        0
attr                    2.5.2         1      0        1          0        0
avahi                   0.8           26     24       1          1        0
avahi-libnss-mdns       0.15.1        0      0        0          0        0
base-files              3.0.14        1      0        0          1        0
base-passwd             3.6.8         0      0        0          0        0
bash                    5.3           18     18       0          0        0
bash-completion         2.17.0        0      0        0          0        0
bluez5                  5.86          43     39       1          3        0
  [...]
zlib                    1.3.2         16     14       2          0        0
zstd                    1.5.7         4      4        0          0        0
TOTAL                                 22445  18522    1073       2850     0

Components: 93; unique CVEs: 22328

Le total fait un peu peur, mais en filtrant avec l’option -f et la liste des packages réellement embarqués sur la cible, les nombres diminuent :

$ ./cve-parse  core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json   -f  core-image-base-qemuarm.rootfs.spdx.json 
COMPONENT               VERSION      TOTAL  PATCHED  UNPATCHED  IGNORED  OTHER
acl                     2.3.2        4      2        2          0        0
alsa-lib                1.2.15.3     6      2        4          0        0
alsa-state              0.2.0        0      0        0          0        0
alsa-ucm-conf           1.2.15.3     0      0        0          0        0
alsa-utils              1.2.15.2     0      0        0          0        0
attr                    2.5.2        1      0        1          0        0
avahi                   0.8          26     24       1          1        0
avahi-libnss-mdns       0.15.1       0      0        0          0        0
base-files              3.0.14       1      0        0          1        0
base-passwd             3.6.8        0      0        0          0        0
bluez5                  5.86         43     39       1          3        0
busybox                 1.37.0       51     47       4          0        0
dbus                    1.16.2       26     26       0          0        0
dosfstools              4.2          2      2        0          0        0
eudev                   3.2.14       0      0        0          0        0
expat                   2.7.5        70     59       11         0        0
glib-2.0                2.88.2       35     35       0          0        0
glibc                   2.43+git     179    159      16         4        0
init-ifupdown           1.0          0      0        0          0        0
init-system-helpers     1.69         0      0        0          0        0
initscripts             1.0          2      2        0          0        0
kmod                    34.2         0      0        0          0        0
libcap                  2.77         5      5        0          0        0
libdaemon               0.14         0      0        0          0        0
libffi                  3.5.2        1      1        0          0        0
libgcc                  15.3.0       16     16       0          0        0
libpcre2                10.47        19     11       8          0        0
libtirpc                1.3.7        5      5        0          0        0
libx11                  1.8.13       22     18       4          0        0
libxau                  1.0.12       0      0        0          0        0
libxcb                  1.17.0       1      1        0          0        0
libxcrypt               4.5.2        0      0        0          0        0
libxdmcp                1.1.5        1      1        0          0        0
libxml2                 2.15.2       120    111      9          0        0
linux-yocto             6.18.39+git  20851  17061    952        2838     0
modutils-initscripts    1.0          0      0        0          0        0
ncurses                 6.6          31     31       0          0        0
netbase                 6.5          0      0        0          0        0
openssl                 3.5.7        322    299      23         0        0
opkg-utils              0.7.0        0      0        0          0        0
packagegroup-base       1.0          0      0        0          0        0
packagegroup-core-boot  1.0          0      0        0          0        0
psplash                 0.1+git      0      0        0          0        0
readline                8.3          1      1        0          0        0
rpcbind                 1.2.8        4      4        0          0        0
shadow                  4.19.4       13     12       0          1        0
shadow-securetty        4.6          0      0        0          0        0
shared-mime-info        2.4          0      0        0          0        0
sysvinit                3.14         0      0        0          0        0
sysvinit-inittab        2.88dsf      0      0        0          0        0
tar                     1.35         20     17       2          1        0
ttyrun                  2.41.0       1      1        0          0        0
update-rc.d             0.8+git      0      0        0          0        0
util-linux              2.41.5       35     28       7          0        0
xz                      5.8.2        9      8        0          1        0
zlib                    1.3.2        16     14       2          0        0
TOTAL                                21939  18042    1047       2850     0

Components: 56; unique CVEs: 21936

Pour chaque composant logiciel, nous obtenons :

  • son numéro de version,
  • le nombre total d’enregistrements CVE,
  • le nombre de CVE auxquelles Yocto attribut l’état « corrigée » (Patched),
  • celles encore non corrigées (Unpatched),
  • celles explicitement ignorées (Ignored),
  • les éventuels autres états (je n’en ai pas rencontré encore).

Le nombre concernant le noyau Linux est particulièrement spectaculaire : plus de 20 000 entrées ! Il ne faut évidemment pas interpréter cette colonne comme signifiant que notre système embarqué contient 20 000 vulnérabilités exploitables. Le nombre de CVE attribuées au noyau Linux a considérablement augmenté ces dernières années et le travail important consiste justement à déterminer quelles vulnérabilités concernent réellement la configuration, les sources compilées et l’utilisation du noyau dans notre produit.

Examiner un composant

Intéressons-nous par exemple au composant acl, pour lequel le résumé indiquait quatre CVE, dont deux non corrigées. L’option -c ou --component permet d’obtenir la liste correspondante :

$ ./yocto-cve-parser/cve-parse  core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json -f core-image-base-qemuarm.rootfs.spdx.json  -c acl

COMPONENT  VERSION  CVE             STATUS     CVSS  SCORE  SEVERITY
acl        2.3.2    CVE-2018-25320  Patched    4.0   9.3    Critical
acl        2.3.2    CVE-2026-54369  Unpatched  4.0   8.4    High
acl        2.3.2    CVE-2026-54370  Unpatched  4.0   7.2    High
acl        2.3.2    CVE-2009-4411   Patched    2.0   3.7    Low

On voit immédiatement que les deux entrées qui méritent notre attention sont :

  • CVE-2026-54369
  • CVE-2026-54370

toutes deux classées en criticité élevée et signalées comme Unpatched. Le tableau indique également la version CVSS utilisée et le score correspondant.

Obtenir tous les détails

L’option -d ou --details permet d’afficher les informations complètes disponibles dans le rapport Yocto :

$ ./cve-parse  core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json  -f ~/core-image-base-qemuarm.rootfs.spdx.json  -c acl  -d
component: acl
version: 2.3.2
layer: core
cve: CVE-2018-25320
status: Patched
cvss: 4.0
score: 9.3
severity: Critical
issue.id: CVE-2018-25320
issue.status: Patched
issue.link: https://nvd.nist.gov/vuln/detail/CVE-2018-25320
issue.summary: ACL Analytics versions 11.x through 13.0.0.579 contain an arbitrary code execution vulnerability that allows attackers to execute arbitrary commands by leveraging the EXECUTE function. Attackers can use bitsadmin to download malicious PowerShell scripts and execute them with system privileges to establish reverse shells and gain complete system control.
issue.scorev2: 0.0
issue.scorev3: 9.8
issue.scorev4: 9.3
issue.modified: 2026-10-01T15:19:15.000
issue.vector: NETWORK
issue.vectorString: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
issue.detail: version-not-in-range: Only affects 11.0 onwards

component: acl
version: 2.3.2
layer: core
cve: CVE-2026-54369
status: Unpatched
cvss: 4.0
score: 8.4
severity: High
issue.id: CVE-2026-54369
issue.status: Unpatched
issue.link: https://nvd.nist.gov/vuln/detail/CVE-2026-54369
issue.summary: acl before version 2.4.0 contains a symlink traversal vulnerability in the libacl pathname-based functions acl_get_file(), acl_set_file(), acl_extended_file(), and acl_delete_def_file() that allows local attackers to escalate privileges by replacing any pathname component with a symbolic link. Attackers who control any component of a pathname processed by a privileged caller can redirect ACL read or write operations to arbitrary files or directories, enabling unauthorized manipulation of access control lists and local privilege escalation.
issue.scorev2: 0.0
issue.scorev3: 7.1
issue.scorev4: 8.4
issue.modified: 2026-09-14T13:18:40.000
issue.vector: LOCAL
issue.vectorString: CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
issue.detail: version-in-range
issue.description: Needs backporting (fixed from 2.4.0)

component: acl
version: 2.3.2
layer: core
cve: CVE-2026-54370
status: Unpatched
cvss: 4.0
score: 7.2
severity: High
issue.id: CVE-2026-54370
issue.status: Unpatched
issue.link: https://nvd.nist.gov/vuln/detail/CVE-2026-54370
issue.summary: acl before version 2.4.0 contains a time-of-check to time-of-use (TOCTOU) race condition vulnerability that allows local attackers to escalate privileges by replacing a pathname component with a symbolic link between an lstat() check and subsequent symlink-following operations such as stat(), chown(), chmod(), acl_get_file(), and acl_set_file(). Attackers who control a pathname component can redirect file access control list operations to arbitrary files when getfacl, setfacl, or chacl is invoked by a privileged process over an attacker-controlled path, resulting in local privilege escalation.
issue.scorev2: 0.0
issue.scorev3: 6.3
issue.scorev4: 7.2
issue.modified: 2026-07-14T21:33:49.000
issue.vector: LOCAL
issue.vectorString: CVSS:4.0/AV:L/AC:H/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
issue.detail: version-in-range
issue.description: Needs backporting (fixed from 2.4.0)

  [...]

Prenons par exemple la vulnérabilité CVE-2026-54369, on voit que :

  • la vulnérabilité est considérée comme applicable à la version utilisée (issue.detail: version-in-range)
  • son vecteur d’attaque est local (issue.vector: LOCAL),
  • elle peut conduire à un gain de privilège (issue.summary: [...] to escalate privileges [...]),
  • une correction existe à partir de la version 2.4.0 mais nécessite un backport.

Ce sont ces données que nous pourrons ensuite utiliser pour déterminer si notre produit est vulnérable ou non en étudiant le contexte d’utilisation de ce composant logiciel. Et faire éventuellement un signalement conforme au Cyber Resilience Act, comme je l’avais développé dans l’article précédent.

Rechercher directement une CVE

Le chemin inverse est également fréquent. Supposons que nous recevions une alerte nous indiquant que CVE-2026-54370 mérite une attention particulière. La question devient « cette vulnérabilité est-elle présente dans mon image, et quel composant concerne-t-elle ? »

L’option cve de cve-parse permet cette recherche directement :

$ ./cve-parse  core-image-base-qemuarm.rootfs.sbom-cve-check.yocto.json  -f core-image-base-qemuarm.rootfs.spdx.json  cve CVE-2026-54370
component: acl
version: 2.3.2
layer: core
cve: CVE-2026-54370
status: Unpatched
cvss: 4.0
score: 7.2
severity: High
issue.id: CVE-2026-54370
issue.status: Unpatched
issue.link: https://nvd.nist.gov/vuln/detail/CVE-2026-54370
issue.summary: acl before version 2.4.0 contains a time-of-check to time-of-use (TOCTOU) race condition vulnerability that allows local attackers to escalate privileges by replacing a pathname component with a symbolic link between an lstat() check and subsequent symlink-following operations such as stat(), chown(), chmod(), acl_get_file(), and acl_set_file(). Attackers who control a pathname component can redirect file access control list operations to arbitrary files when getfacl, setfacl, or chacl is invoked by a privileged process over an attacker-controlled path, resulting in local privilege escalation.
issue.scorev2: 0.0
issue.scorev3: 6.3
issue.scorev4: 7.2
issue.modified: 2026-07-14T21:33:49.000
issue.vector: LOCAL
issue.vectorString: CVSS:4.0/AV:L/AC:H/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
issue.detail: version-in-range
issue.description: Needs backporting (fixed from 2.4.0)

Ce mode me semble particulièrement intéressant dans le cadre du suivi de sécurité d’un produit. Lorsqu’une nouvelle vulnérabilité est publiée ou qu’une CVE fait l’objet d’une alerte, on peut très rapidement vérifier si elle apparaît dans le rapport de l’image produite.

Les CVE du Kernel

Le cas du noyau Linux mérite un traitement particulier. Plus de 20 000 entrées CVE apparaissent ici ! Ceci ne signifie heureusement pas que notre noyau est affecté par 20 000 vulnérabilités exploitables. La configuration du noyau, les fichiers réellement compilés et les correctifs backportés doivent être pris en compte.

Comment réduire cette liste à quelque chose de réellement exploitable ? Cela fera l’objet d’un prochain article…

Limitations

Il est important de préciser ce que fait et ce que ne fait pas cve-parse. L’outil ne dispose pas de sa propre base de vulnérabilités et ne remplace aucun des mécanismes fournis par Yocto. Il ne permet pas non plus de savoir de manière automatique si une vulnérabilité est exploitable ou non sur un équipement. Il se contente d’un rôle plus simple : présenter de manière pratique les informations déjà produites par Yocto Project pour filtrer celles qui nécessiteront des investigations plus poussées.

Le dépôt est disponible ici : https://github.com/cpb-/yocto-cve-parser

N’hésitez pas à le tester sur vos propres rapports Yocto et à me signaler les cas particuliers, formats ou options qui pourraient être utiles.

Conclusion

Produire une SBOM et un rapport de vulnérabilités est une première étape indispensable pour maîtriser la sécurité d’un système Linux embarqué. Mais collecter les informations ne suffit pas : il faut également être capable de les exploiter rapidement lorsqu’une nouvelle vulnérabilité apparaît. Avec cve-parse, on peut passer en quelques secondes d’un aperçu général des vulnérabilités dans une image, à la liste des CVE associées à un composant, puis au détail d’une vulnérabilité précise.

L’outil évoluera probablement en fonction de mes besoins et des retours d’utilisation. Son objectif restera néanmoins le même : rendre les rapports de sécurité produits par Yocto Project plus faciles à lire et à exploiter.

URL de trackback pour cette page