npm audit annonce 37 failles : trier celles qui vous concernent
Sur un audit récent, npm audit annonçait 37 vulnérabilités dont 7 de gravité haute.
Après vérification, une seule était atteignable depuis le code de
l’application. Les 36 autres étaient réelles, publiées, correctement signalées, et
sans effet ici.
Ce n’est pas un défaut de l’outil. npm audit fait ce qu’il annonce : il compare
l’arbre de dépendances à une base d’avis de sécurité. Il ne sait pas quelles
fonctions vous appelez, avec quelles valeurs, ni si le paquet fautif tourne en
service ou seulement pendant la construction. Ce tri-là, personne ne le fait à
votre place.
Voici la méthode que j’applique. Elle prend une à deux heures sur un projet de taille moyenne, et elle évite les deux réflexes habituels : tout mettre à jour dans la panique, ou ne rien faire parce que le chiffre est décourageant.
1. Séparer ce qui tourne en service de ce qui ne tourne pas
C’est le tri qui élimine le plus de bruit, et il coûte une commande.
npm audit --omit=dev
Une faille dans un paquet utilisé uniquement au moment de la construction n’est pas exploitable par un visiteur. Elle reste un risque pour votre chaîne de livraison, ce qui est un sujet sérieux, mais ce n’est pas le même sujet et ça ne se traite pas avec la même urgence.
Sur le projet en question, cette seule commande faisait tomber le décompte de 37 à 19.
Attention à un cas particulier : un outil de construction qui lit des données
fournies par un tiers pendant la construction, par exemple un générateur de site
qui interprète du Markdown venu d’un dépôt public, est bel et bien exposé. La
frontière n’est pas devDependencies, elle est « est-ce que des données non
maîtrisées passent par là ».
2. Remonter à la fonction, pas au paquet
Un avis de sécurité décrit presque toujours un chemin précis : telle fonction, tel paramètre, telle valeur. Lisez-le, puis cherchez si ce chemin existe chez vous.
L’exemple le plus parlant de cet audit : onze avis concernaient Nodemailer. Sept en gravité haute. De quoi s’inquiéter, jusqu’à lire lesquels.
Les onze portaient sur l’analyse d’adresses malformées, sur des en-têtes
construits à partir de valeurs non contrôlées, et sur des pièces jointes dont le
nom vient de l’extérieur. Or dans cette application, sendMail ne reçoit que six
champs, tous construits par le code :
await transport.sendMail({
from, to, replyTo, // composés à partir de la configuration du site
subject, text, html, // gabarits internes
})
Aucune pièce jointe. Aucun en-tête libre. Aucune adresse saisie par un visiteur n’atteint la fonction sans être passée par une validation en amont. Les onze avis décrivent des entrées que cette application n’a pas.
La mise à jour reste souhaitable, et elle a été faite. Mais elle est passée de « ce soir » à « au prochain lot », ce qui change la façon dont on organise sa semaine.
3. Écrire la chaîne d’exploitation, ou admettre qu’on n’y arrive pas
Pour chaque avis qui survit aux deux premiers tris, écrivez la chaîne complète : qui appelle, avec quoi, et ce qu’il obtient. En trois lignes.
Qui : n'importe qui, sans compte
Comment : appelle /api/x avec un identifiant arbitraire
Résultat : lit l'adresse et le moyen de paiement d'un autre membre
Si vous n’y arrivez pas, deux cas. Soit vous manquez d’information sur votre propre code, et c’est une découverte utile en soi. Soit la faille n’est pas atteignable, et vous venez de l’établir plutôt que de le supposer.
Cette écriture a un effet secondaire que je n’attendais pas : elle rend le rapport lisible par quelqu’un qui ne code pas. Un dirigeant comprend « n’importe qui peut lire l’adresse d’un client ». Il ne comprend pas « prototype pollution dans lodash 4.17.20 », et il a raison de ne pas comprendre.
4. Noter les faux positifs écartés, avec leur raison
C’est l’étape qu’on saute le plus souvent, et celle qui coûte le plus cher.
Six mois plus tard, quelqu’un relance npm audit, retrouve les mêmes 36 avis, et
refait le même travail. J’ai vu ce cycle se répéter trois fois sur le même
projet, par trois personnes différentes, dont moi.
Le rapport doit donc contenir une section qui dit, pour chaque avis écarté, pourquoi il l’a été. Deux lignes suffisent :
Nodemailer, 11 avis (7 hautes). Écartés :
sendMailne reçoit quefrom,to,replyTo,subject,text,html, tous construits par le code. Aucune pièce jointe, aucun en-tête libre. Vérifié le 2026-09-23 sur la version 6.9.14.
Avec la date et la version, parce que l’argument cesse d’être vrai le jour où quelqu’un ajoute les pièces jointes.
La mise à jour reste obligatoire
Elle ne remplace pas la mise à jour. Une dépendance qu’on ne met jamais à jour finit par accumuler assez de retard pour que la montée devienne un chantier à part entière, et c’est un piège plus coûteux que les failles elles-mêmes.
Elle ne dit rien non plus des failles qui ne sont pas encore publiées, ni de celles de votre propre code, qui sont statistiquement plus nombreuses et plus graves que celles de vos dépendances.
Enfin, elle demande de lire des avis de sécurité, ce qui prend du temps et suppose de comprendre le paquet concerné. Sur un projet où vous ne connaissez pas la moitié de l’arbre de dépendances, le tri sera partiel et il faut le dire dans le rapport plutôt que de faire semblant.
Un chiffre n’est pas une mesure
Le chiffre que rend npm audit est une liste de candidats, pas une mesure de
risque. Le travail consiste à passer de 37 candidats à un nombre de failles
réelles, et à garder la trace de ce raisonnement pour que la personne suivante
n’ait pas à le refaire.
Sur l’audit cité, le rapport final tient en une faille atteignable, son correctif, et trente-six lignes qui disent pourquoi les autres ont été écartées. Ces trente-six lignes sont la partie qui servira le plus dans six mois.