Le réflexe est naturel : avant d'implémenter une fonctionnalité, chercher si un package NuGet ne la couvre pas déjà. Un nom arrive, depuis une documentation, une recherche ou une réponse d'agent ; il semble correspondre au besoin, puis l'intégration suit. C'est précisément dans ce court intervalle, entre découverte et ajout au projet, qu'un package conçu pour tromper passe le plus facilement : il n'a pas encore de CVE au moment de sa diffusion, il n'apparaît dans aucun scanner, et son nom est choisi pour ne pas déclencher d'alerte.
Cet article ne traite pas les mécanismes d'attaque eux-mêmes : ils font l'objet d'un article de contextualisation dédié. Il ne couvre pas non plus la dimension organisationnelle de la décision, qui sera traitée dans un futur article sur la gouvernance des dépendances. Son objectif est plus resserré : outiller un seul moment, de la recherche d'un package à la décision de l'intégrer.
Périmètre
Évaluation d'un package inconnu sur nuget.org, accessible publiquement, depuis la
recherche jusqu'à la décision d'intégration, avec les outils standard du développeur
.NET (page nuget.org, CLI dotnet, Package Manager de Visual Studio),
complétés de corroborations externes publiquement accessibles quand un signal
l'exige. Les
flux NuGet privés,
l'audit binaire post-intégration et la maintenance des dépendances dans le temps sont
hors périmètre. La réponse finale dépend toujours du contexte : criticité du package,
existence d'alternatives, coût d'une implémentation interne.
Ce que les outils ne font pas
Les outils intégrés à NuGet (NuGetAudit, lock files et Package Source Mapping) détectent des vulnérabilités connues dans des packages déjà intégrés et contrôlent les sources ou les versions autorisées. Aucun ne dit si un package inconnu mérite d'être intégré au projet. Les scanners tiers (Socket, ReversingLabs) analysent le catalogue en continu et signalent les packages malveillants à nuget.org pour suppression. Cette détection réduit la fenêtre d'exposition, parfois à quelques jours, sans l'annuler. Pendant cette fenêtre, l'évaluation au moment du choix reste la barrière active côté développeur.
C'est cette lacune que la grille ci-dessous vise à combler : utiliser les signaux observables sur nuget.org pour se forger une opinion avant d'intégrer un package.
La grille de signaux
La grille est ordonnée par priorité analytique, du signal le plus discriminant au plus contextuel. Aucun critère ne tranche seul : c'est leur lecture combinée, replacée dans le contexte du projet, qui permet de construire une opinion. Le processus en fin d'article reprend ces signaux dans l'ordre où ils interviennent concrètement, de la recherche du package à la décision.
| # | Signal | Question à se poser |
|---|---|---|
| 1 | Le nom | Le nom pourrait-il être confondu avec un package officiel ? Par quel chemin est-il arrivé ? |
| 2 | Le publisher / owners | L'identité est-elle cohérente avec ce que le package prétend être ? |
| 3 | Le badge Prefix Reserved | Le package de référence le porte-t-il ? Le candidat l'a-t-il ? |
| 4 | Vulnérabilité et version | La page signale-t-elle une vulnérabilité ? La version visée est-elle la plus récente ? |
| 5 | Le dépôt source | Le dépôt est-il accessible, et le binaire publié en provient-il réellement ? |
| 6 | La licence | Est-elle renseignée et compatible avec le contexte du projet ? |
| 7 | La popularité | La trajectoire des téléchargements est-elle cohérente avec l'histoire du package ? |
| 8 | La signature | Qui assume publiquement et de façon vérifiable la publication ? |
| 9 | La maintenance | Si le mainteneur disparaît demain, quel est l'impact ? |
| 10 | Les dépendances | Que tire le package, et qu'est-ce qui sort de l'ordinaire ? |
Pour situer les signaux sur une page réelle, Newtonsoft.Json sert d'illustration : une bibliothèque de référence, largement adoptée et identifiable, dont la page rassemble tous les éléments de la grille. La section exemple en fin d'article déroule la grille complète sur deux profils synthétiques plus proches du cas courant.
Newtonsoft.Json en version 12.0.3. Les éléments numérotés
renvoient aux signaux de la grille : badge de préfixe réservé, owners identifiables,
bandeau de vulnérabilité sur cette version, indication d'une version plus récente
disponible, project website, source repository et licence MIT. Un package parfaitement
légitime peut être un mauvais choix d'intégration à une version donnée : ici, la 12.0.3
porte une vulnérabilité corrigée dans les versions ultérieures. Capture de juin 2026 ;
la mise en page de nuget.org peut évoluer, les signaux décrits restent identifiables.
1. Le nom du package
Le typosquatting
joue sur des variations ASCII : inversion de termes, ajout de segments courants comme
NetCore ou Common, redondance, lettre substituée. Ces
variations sont visibles, à condition de connaître la nomenclature habituelle du
domaine. L'origine du nom est donc décisive : un identifiant issu de la documentation
officielle n'a pas le même poids qu'un nom trouvé via la recherche nuget.org sur un
terme fonctionnel, ou récupéré depuis une source externe non vérifiée (chat, ticket,
réponse d'agent).
L'attaque par homoglyphes, historiquement significative, consiste à substituer un
caractère par un autre visuellement identique mais de code différent : un "о"
cyrillique (U+043E) à la place du "o" latin rend Newtоnsoft.Json
indiscernable de Newtonsoft.Json dans les polices courantes. Ce vecteur a
été exploité dans des attaques documentées, dont le cas
Netherеum.All
(Socket, octobre 2025), rendu possible par une validation des identifiants historiquement
plus permissive que celles de npm et PyPI, elles-mêmes restreintes à l'ASCII. En
juin 2026, NuGet a annoncé (NuGet/Announcements#75)
l'alignement de nuget.org sur ces registres : restriction ASCII sur les identifiants
des nouveaux packages, avec un déploiement par phases à partir du 15 juin 2026. Ce
durcissement ferme le vecteur homoglyphe pour les publications futures. Il ne porte
pas sur le stock : les identifiants non-ASCII déjà publiés restent en place par liste
d'exception, et restent installables.
L'inspection des octets reste donc le contrôle systématique sur tout identifiant
copié depuis une source non vérifiée : la restriction ASCII ne s'applique pas au stock
déjà publié, et rien, dans une ligne d'installation par identifiant et version, ne
distingue un package antérieur au durcissement d'un package récent. La saisie manuelle
sur une disposition latine écarte souvent l'homoglyphe d'elle-même ; le copier-coller,
lui, conserve la chaîne exacte, homoglyphes compris. Le contrôle tient en une commande
(Format-Hex en PowerShell sous Windows, hexdump -C sous Linux) :
PS> 'Newtоnsoft.Json' | Format-Hex
Label: String (System.String) <35B53910>
Offset Bytes Ascii
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
------ ----------------------------------------------- -----
0000000000000000 4E 65 77 74 D0 BE 6E 73 6F 66 74 2E 4A 73 6F 6E Newtоnsoft.Json
La séquence d0 be apparaît là où un seul octet 6f est attendu :
tout octet au-delà de 7f sur un nom censé être latin devient une anomalie
visible immédiatement. Les éditeurs récents offrent un premier filet : VS
Code souligne par défaut les caractères confusables avec l'ASCII
(editor.unicodeHighlight.ambiguousCharacters). C'est un signal heuristique
utile, mais il ne remplace pas le contrôle des octets.
Indépendamment des homoglyphes, un comportement du registre reste à connaître : un
package retiré des résultats de recherche
(non répertorié ou délisté)
reste installable dès lors que l'ID et la version exacte sont fournis :
dotnet add package Newtonsoft.Json -v 13.0.3 ne passe pas par le filtre
du listing. Une ligne copiée depuis une source non vérifiée peut donc installer un
package qui n'apparaîtra jamais dans une recherche.
En clair : ce nom peut-il être confondu avec un package officiel, et d'où vient-il exactement ?
Ce que nuget.org bloque à l'upload, et ce qu'il ne bloque pas
Le code source de la galerie NuGet, publié sur
GitHub, montre qu'un contrôle de typosquatting
(TyposquattingService) existe à l'upload. Le nouvel identifiant est comparé
à une liste de référence construite à partir des packages existants, priorisée
(packages vérifiés d'abord, puis les plus téléchargés) et tronquée à une longueur
configurée. Si l'identifiant est jugé trop proche d'une entrée et que le package en
collision n'appartient pas au même compte, l'upload est refusé.
Deux limites apparaissent dans le code. La comparaison est contournée si l'identifiant relève d'un préfixe déjà réservé. Et la liste de référence étant tronquée et priorisée sur la popularité, un package de niche a une probabilité réduite d'y figurer : un typosquat qui l'imite n'a rien à quoi être comparé.
Sa capacité historique à détecter les homoglyphes reste, elle, invérifiable :
l'implémentation de repli du dépôt public ne fait qu'une comparaison stricte après
mise en minuscule, et l'algorithme de production est
chargé comme un
composant additionnel non inclus dans le dépôt public. Le cas
Netherеum.All, publié le 16 octobre 2025, signalé par Socket
le 18 et retiré le 20, est cohérent avec une détection absente ou incomplète à
l'upload. La restriction ASCII de juin 2026 rend la question sans objet pour les
nouveaux identifiants, en la tranchant en amont.
2. Le publisher / owners
Sur nuget.org, les owners sont affichés sur la page du package, sous forme de lien vers le
profil de chaque compte. Ce profil affiche l'ancienneté du compte et ses autres
publications. À observer : le volume et la nature de ces packages, puis la cohérence
entre l'identité déclarée et le domaine. Un compte créé il y a trois semaines avec un
seul package qui wrappe une bibliothèque majeure pose des questions différentes d'un compte
avec cinq ans d'historique et une dizaine de packages dans le même domaine. En ligne de
commande, le champ Owners de dotnet package search reste
l'indicateur d'identité le plus exploitable.
Le nom de compte lui-même n'est pas à l'abri de l'imitation. Les noms d'utilisateur nuget.org sont restreints aux caractères ASCII (lettres, chiffres, underscore, point, tiret), comme le définit la règle de validation du code source de la galerie : l'homoglyphe cyrillique ou grec, possible sur un nom de package, ne l'est pas sur un nom de compte. En revanche, rien n'empêche un compte nommé de façon visuellement proche d'un compte légitime (lettre substituée, suffixe ajouté), et le mécanisme de litige documenté par nuget.org intervient après création du compte. Un nom de publisher plausible, pris seul, reste donc soumis au même doute qu'un nom de package pris seul.
À vérifier : l'identité des owners est-elle cohérente avec ce que le package prétend être, et confirmée par autre chose que le nom du compte ?
3. Le badge Prefix Reserved
Le badge "Prefix Reserved" est le signal le plus fiable sur l'identité du publisher. Il garantit que le package qui l'affiche appartient au propriétaire du préfixe réservé : un attaquant ne peut pas publier sous ce préfixe sans en être l'owner validé. C'est pour cette raison que le raccourci de confiance n'est jamais le nom de publisher seul, mais le nom associé au badge : le nom peut être imité (signal 2), le badge confirme qu'il ne l'est pas. En présence d'un package de référence avec badge, tout concurrent sans badge est immédiatement distinguable. Le mécanisme de réservation de préfixe est documenté par Microsoft.
Trois limites à garder en tête. Le badge n'est visible que sur nuget.org et dans le Package Manager de Visual Studio : il n'apparaît pas en CLI. Sur les domaines de niche, il n'existe souvent pas : aucun publisher n'a fait la démarche, et les candidats se présentent alors à égalité. Enfin, il confirme l'identité du compte au moment de la réservation, pas l'intégrité de tout ce qui a accès à ce compte dans la durée (voir signal 9).
4. Vulnérabilité connue et fraîcheur de version
La page du package signale directement, via un bandeau en haut de page, si la version consultée porte une vulnérabilité connue et si une version plus récente existe. Un package parfaitement légitime peut porter une vulnérabilité : sur une version ancienne, corrigée depuis, ou sur sa dernière version, pas encore corrigée. La décision d'intégration porte donc autant sur la version visée que sur le package lui-même.
Cette vérification au moment du choix est distincte de la surveillance continue dans le
pipeline de build (dotnet list package --vulnerable), qui relève de la
maintenance des dépendances et fait l'objet d'un article séparé. La question est simple :
la version que je m'apprête à intégrer est-elle saine et à jour ?
5. Le dépôt source
Pour un package open source, l'absence de dépôt accessible pose une question directe : comment évaluer le code intégré, et comment le réévaluer lors des montées de version ? Un dépôt non accessible ou en 404 arrête l'évaluation. L'absence pure et simple du champ source repository est elle-même un signal : un publisher qui documente son package renseigne généralement ce champ.
Le problème de la déclarativité
Un dépôt qui répond n'est pourtant pas une garantie : le champ est déclaratif, nuget.org ne vérifie pas que le package publié en provient réellement. Rien n'empêche un package malveillant de pointer vers le vrai dépôt du projet légitime qu'il imite. Deux contrôles complémentaires s'imposent.
Contrôle 1 : Cohérence versions NuGet et releases du dépôt
L'onglet Versions de la page nuget.org liste les versions publiées avec leur date. Une version publiée sur nuget.org qui ne correspond à aucune release du dépôt déclaré rompt le lien que le champ prétend établir.
Contrôle 2 : Cohérence avec des sources datées indépendantes
Les dates d'historique git sont des données client, modifiables avant envoi, que les plateformes d'hébergement acceptent sans validation. Ce qui devient coûteux à falsifier, c'est la corroboration externe : la Wayback Machine sur l'URL du dépôt, des mentions datées antérieures à la création revendiquée, la date de première publication sur nuget.org. Un dépôt qui revendique trois ans d'historique mais dont la première capture date de la semaine dernière pose une question concrète.
À vérifier : l'ancienneté et le contenu revendiqués par le dépôt trouvent-ils une corroboration indépendante du dépôt lui-même ?
Le cas des packages propriétaires
Un SDK commercial n'expose pas son code par nature. L'absence de dépôt n'y est pas un signal suspect : c'est une caractéristique du modèle. Les questions se déplacent vers l'éditeur : est-il identifiable et établi ? Le package est-il signé par un certificat rattaché à l'organisation ? Existe-t-il un support officiel et une politique de versioning documentée ?
6. La licence
La page indique la licence. Son absence est un signal en soi : sans licence explicite, le droit d'utiliser le package dans le projet n'est pas établi. Les questions de compatibilité (GPL dans un projet commercial, changement de licence entre versions) se traitent avant l'intégration, indépendamment de la sécurité : Choose a License et la SPDX License List donnent les repères nécessaires. À vérifier : cette licence est-elle renseignée, stable entre versions, et compatible avec le contexte du projet ?
7. La popularité
Le volume de téléchargements peut être gonflé artificiellement par scripting : le cas
Netherеum.All (signal 1) montre qu'aucun mécanisme côté nuget.org ne
l'a empêché en pratique. Ce n'est donc pas un signal de confiance en soi, et il n'existe
pas de seuil universel : la taille des domaines fonctionnels varie trop pour qu'un
chiffre fasse office de référence. Ce qui reste exploitable, c'est la trajectoire du
package au regard de sa propre histoire. L'onglet Versions affiche la
répartition des téléchargements par version : une progression étalée dans le temps
raconte une adoption réelle ; un volume concentré sur une version récente, en quelques
jours, raconte l'inverse. C'est ce qui a été observé sur
Netherеum.All
(homoglyphe cyrillique du package Nethereum, documenté par Socket en octobre 2025) :
11,6 millions de téléchargements générés par scripting en quelques jours, sans
historique antérieur cohérent.
Ce cas visait précisément le raccourci mental "beaucoup de téléchargements, donc adoption
suffisante". La lecture de trajectoire est elle aussi contournable : le cas
StripeApi.Net
(ReversingLabs, février 2026) a réparti environ 180 000 téléchargements artificiels sur
506 versions, simulant une progression organique. La trajectoire élimine donc le pic
grossier, pas la fabrication patiente : elle reste nécessaire, jamais suffisante seule,
et doit se recouper avec la cohérence des versions face aux releases du dépôt (signal 5).
Un volume élevé n'est un raccourci légitime que s'il est cohérent avec la trajectoire du
package. À vérifier : cette trajectoire est-elle compatible avec l'âge du package et sa
communauté visible ?
8. La signature du package
Deux signatures peuvent exister : la signature d'auteur (certificat propre du
développeur) et la signature de dépôt (contre-signature nuget.org à la publication).
Contrairement aux autres signaux, ce détail n'est pas exposé sur la page nuget.org
(constaté en juillet 2026) : il s'observe dans NuGet Package Explorer, section
Digital Signatures (outil présenté plus bas), ou via
dotnet nuget verify sur le .nupkg téléchargé. Ce signal reste
faible dans les deux sens : une signature ne garantit pas l'innocuité du code, et son
absence ne prouve pas la malveillance. Sa valeur est d'abord la traçabilité : un
certificat rattaché à une organisation connue permet de vérifier qui assume publiquement
la publication. C'est un signal de confirmation pour un package qui passe déjà les autres
critères, pas un critère discriminant. À vérifier : qui assume publiquement, et de façon
vérifiable, la publication de ce package ?
9. Maintenance active
Un package sans maintenance active présente deux risques. D'abord les vulnérabilités : une CVE découverte sur un package abandonné ne sera pas corrigée. Ensuite la prise de contrôle du compte publisher (account takeover) : un mainteneur inactif est une cible, et l'attaquant qui reprend le compte publie une version compromise en héritant de toute la confiance accumulée. Les signaux observables sont la date de la dernière release (onglet Versions), l'activité du dépôt et la réactivité sur les issues.
Comme pour la popularité, la référence la plus fiable est le rythme propre au package. Un package qui publiait tous les deux mois pendant trois ans et n'a rien publié depuis quatorze mois envoie un signal, indépendamment des cycles de release de l'écosystème. À l'inverse, un package trop récent pour offrir un historique exploitable est aussi un signal : si le besoin n'est pas urgent, différer l'intégration de quelques semaines est une réponse légitime. À vérifier : si le mainteneur disparaît demain, quel est l'impact pour le projet, et ce risque est-il acceptable au regard de la criticité de la dépendance ?
10. Les dépendances
Un package peut tirer ses propres dépendances, qui tirent les leurs. Si A dépend de B qui dépend de C, C est une dépendance transitive de A. Beaucoup de packages n'en déclarent aucune, et cette absence se constate en un regard ; c'est le cas contraire qui demande l'examen. Le package évalué peut être sain et tirer une dépendance vulnérable ou malveillante : l'évaluer sans regarder ce qu'il embarque laisse un angle mort.
Avant intégration, l'onglet Dependencies de la page nuget.org, à la version précise, liste les dépendances déclarées sans rien installer. Il ne s'agit pas d'auditer toute l'arborescence transitive, parfois large et profonde, mais de repérer ce qui sort de l'ordinaire parmi les dépendances directes : une dépendance exotique ou inconnue mérite le même niveau d'attention, sa page est à quelques clics. Après intégration, la ligne de commande confirme sur le projet ce que la page a laissé voir avant :
# Arborescence complète, dépendances transitives incluses
$ dotnet list package --include-transitive
# Dépendances ayant une vulnérabilité connue
$ dotnet list package --vulnerable --include-transitive
# Comprendre pourquoi un package transitif est présent
$ dotnet nuget why <projet> <packageId>
À vérifier : qu'est-ce que ce package tire, et ai-je regardé ce qui sort de l'ordinaire ?
Inspecter le package sans l'installer
Plusieurs signaux de la grille butent sur la même limite : la page nuget.org décrit le
package, mais ne l'ouvre pas.
NuGet Package
Explorer (open source, .NET Foundation), disponible en version web sur
nuget.info, ouvre le .nupkg lui-même. Le
contenu réel du package (assemblies, fichiers .targets ou
.props, ressources embarquées) est consultable sans installation ni
compilation : c'est le moyen le plus direct de voir une cible MSBuild avant exécution.
L'outil apporte deux vérifications absentes de la page nuget.org. Sa section Health contrôle, quand le publisher a activé ces options au build, que le binaire est relié au code source déclaré (Source Link) et que la compilation est reproductible (build déterministe) : une réponse partielle à la nature déclarative du champ source repository du signal 5. Sa section Digital Signatures détaille les signatures d'auteur et de dépôt (émetteur, horodatage) du signal 8, non exposées sur la page du package. L'outil fonctionne aussi sur un package non répertorié, dès lors que l'ID et la version sont connus (constaté en juillet 2026).
Ses limites sont explicites : les dépendances ne sont pas contrôlées, et les signaux propres à la galerie (badge, profil des owners, bandeau de vulnérabilité, répartition des téléchargements) restent sur nuget.org. NPE complète la page, il ne la remplace pas.
Le processus, étape par étape
La documentation officielle indique qu'essayer un package est une bonne façon de l'évaluer, et propose les signaux nuget.org comme alternative plus rapide. Le processus ci-dessous retient la même conclusion pratique (page d'abord), pour une raison différente : l'essai suppose la bonne foi du package, précisément ce que l'évaluation cherche à établir. Un package peut embarquer des cibles MSBuild importées automatiquement à l'ajout et exécutées à la première compilation : essayer un package malveillant, c'est déjà exécuter son code. L'essai vient donc après la grille, pas avant.
La grille décrit ce qu'il faut observer ; le processus ci-dessous reprend ces signaux dans l'ordre où ils interviennent concrètement. Chaque étape renvoie au signal correspondant entre crochets.
- Copier l'identifiant du package depuis sa source. Conserver la chaîne exacte, sans la ressaisir, pour ne pas masquer un éventuel homoglyphe par une saisie "corrigée".
-
Vérifier que c'est une chaîne ASCII. [1] Inspection des octets avec
hexdump -CouFormat-Hex. -
Rechercher l'identifiant exact sur nuget.org. [1] Un
exact match est attendu. Si plusieurs résultats proches apparaissent, la
comparaison entre eux est en soi un signal : variations de nom, owners différents,
présence ou absence de badge. Une absence totale de résultat sur un ID pourtant
installable signifie que le package est non répertorié ou délisté : c'est une
raison d'arrêter et de comprendre pourquoi avant d'aller plus loin. Pour un
identifiant copié depuis une source non vérifiée et pouvant pointer vers un package
antérieur à la restriction ASCII du registre, l'inspection des octets
(
hexdump -C,Format-Hex) reste le contrôle pertinent. - Ouvrir la page du package. [2, 3, 4, 5, 6, 10] La page rassemble d'un coup, sans rien exécuter : owners, badge de préfixe réservé, bandeau de vulnérabilité, fraîcheur de version, dépôt source, licence, et l'onglet des dépendances déclarées. L'absence d'un champ attendu est elle aussi une information.
- Évaluer les signaux que la page ne tranche pas seule. [5, 7, 8, 9, 10] Cohérence du dépôt avec les releases et des sources datées, trajectoire de téléchargements et de releases propre au package, signature et contenu du package via NuGet Package Explorer, maintenance active, regard sur les dépendances qui sortent de l'ordinaire.
-
Décider, et tracer la décision. Le
template de revue
de dépendance disponible en ressource fournit un cadre pour documenter la
décision dans une pull request. Après ajout,
dotnet list package --vulnerable --include-transitiveconfirme l'absence de vulnérabilité connue dans le graphe.
La bonne question n'est pas "est-ce dangereux ?", mais "pourrai-je défendre cette intégration dans six mois ?" Si la réponse est non, c'est suffisant pour chercher une alternative.
Exemple : deux profils de niche face à la grille
Un cas extrême comme Newtonsoft.Json, où tous les signaux convergent, ne
représente pas la situation courante. Le cas difficile est le package de niche : peu de
téléchargements, pas de badge, peu de traces externes. C'est là que la grille doit
différencier deux profils aux signaux faibles. Les deux packages ci-dessous sont
synthétiques : noms, chiffres et URL sont fictifs, mais représentatifs de profils
rencontrés sur nuget.org. Ce choix est volontaire : les packages malveillants documentés
ont été retirés et ne sont plus vérifiables, et citer un package réel encore accessible
reviendrait à associer publiquement un développeur de bonne foi à un article sur les
attaques de
chaîne d'approvisionnement logicielle.
Fabrikam.JsonFlatten et Acme.NetCore.Json occupent le même
domaine fonctionnel, sans badge ni volume notable l'un comme l'autre. Seule remarque
possible avant d'ouvrir leurs pages : le segment NetCore au milieu du
second nom suit un pattern de namespace artificiel, sans rien d'alarmant isolément.
Le reste se lit dans les signaux.
| Signal | Fabrikam.JsonFlatten |
Acme.NetCore.Json |
|---|---|---|
| 1. Nom | ASCII vérifié ; nom descriptif d'une fonction précise ; nomenclature cohérente | ASCII vérifié ; segment NetCore pouvant imiter un namespace officiel |
| 2. Publisher / owners | Compte individuel, 3 ans d'ancienneté, 4 packages dans le même domaine | Compte individuel créé il y a 5 semaines, 1 autre package dans le même domaine |
| 3. Badge Prefix Reserved | Absent | Absent |
| 4. Vulnérabilité / version | Aucun bandeau ; dernière version visée | Aucun bandeau ; dernière version visée |
| 5. Dépôt source | Accessible ; releases alignées sur les versions NuGet ; première capture Wayback cohérente avec l'ancienneté revendiquée | URL renseignée mais en 404 |
| 6. Licence | MIT, stable entre versions | Champ absent |
| 7. Popularité | 4 200 téléchargements répartis sur 9 versions et 3 ans | 340 téléchargements sur 3 versions en 5 semaines |
| 8. Signature | Signature de dépôt uniquement | Signature de dépôt uniquement |
| 9. Maintenance | Releases régulières ; issues traitées sous quelques semaines | Aucun historique exploitable |
| 10. Dépendances | Aucune dépendance directe hors framework | Une dépendance inconnue du même publisher |
Aucun des deux packages n'atteint le niveau de convergence d'un
Newtonsoft.Json, et ce n'est pas ce que la grille demande : ce qui compte
est l'absence de signal contradictoire, pas le nombre de signaux positifs. Sur
Fabrikam.JsonFlatten, les signaux sont faibles mais cohérents entre eux :
l'ancienneté du compte, la trajectoire des téléchargements, le rythme des releases et
les traces externes racontent la même histoire. Les indicateurs sont cohérents. Sur
Acme.NetCore.Json, les lacunes s'accumulent au lieu de se compenser : le
dépôt en 404 empêche de valider le code, l'absence de publisher identifiable laisse la
question de l'imputabilité ouverte, la dépendance inconnue ajoute à la complexité de
l'analyse. La conclusion n'est pas "ce package est malveillant", mais "les questions que
ce profil soulève sont difficiles à résoudre ; le bénéfice justifie-t-il le risque de
les laisser sans réponse ?"
Quand un package est écarté, la suite logique est de chercher une alternative ou d'envisager une implémentation interne si le besoin est circonscrit. Un signalement via nuget.org ne se justifie que si l'analyse révèle des éléments activement suspects : homoglyphe confirmé, pic soudain de téléchargements artificiels, code malveillant. Des métadonnées incomplètes ne suffisent pas.
Limites
- Un package sain au moment de l'évaluation peut devenir malveillant ou vulnérable ensuite. Prise de contrôle du compte publisher, dépendance transitive compromise, version ultérieure compromise, CVE découverte plus tard : les signaux reflètent l'état du package au moment de l'évaluation, pas dans le temps. La surveillance post-intégration est un problème différent.
- Les signaux sont contournables, et leur coût varie. Des dates d'historique git antidatées se fabriquent en quelques heures. Ce qui est réellement coûteux à falsifier, c'est la cohérence avec des sources datées indépendantes du dépôt. La grille élève le coût d'une attaque crédible, elle ne l'élimine pas.
- L'audit binaire reste le dernier recours. Quand l'analyse des signaux ne permet pas de se forger une opinion, ILSpy permet d'inspecter le comportement réel du code compilé. Son coût est élevé : l'audit est à refaire à chaque montée de version.
- Cette grille ne couvre pas les flux NuGet privés. Si un flux privé coexiste avec nuget.org, le vecteur de confusion de dépendances nécessite Package Source Mapping. Hors périmètre ici.
- Sur les domaines de niche, les signaux fiables sont rares. Le badge "Prefix Reserved" n'existe souvent pas, les téléchargements sont naturellement faibles, les traces externes datées sont peu nombreuses, et le contrôle de typosquatting à l'upload ne compare qu'à une liste plafonnée de packages populaires. C'est là que le vecteur d'entrée prend tout son poids : si le nom ne vient pas d'une source faisant autorité, l'ensemble de la grille repose sur des signaux peu discriminants. Une analyse approfondie est souvent nécessaire. Selon le modèle de menace, l'implémentation interne ou le rejet explicite avec justification sont des réponses légitimes.
Conclusion
Ce processus couvre le moment de la découverte, avant que le package n'entre dans le projet. C'est une condition nécessaire, mais pas suffisante : un package sain à l'intégration peut devenir problématique ensuite, et sa surveillance dans le temps relève d'une démarche distincte.
L'objectif de la démarche n'est pas de produire une certitude, mais une opinion documentée et défendable. Dans un contexte professionnel, c'est précisément ce qui est attendu d'une décision d'intégration : non une garantie d'innocuité, mais la trace d'une analyse rigoureuse.
Cet article décrit une démarche d'évaluation fondée sur des signaux publiquement observables, dans l'état constaté à la date de rédaction. Il ne constitue ni une garantie d'innocuité des packages évalués, ni un conseil juridique ou de sécurité couvrant un contexte particulier. La décision d'intégrer une dépendance et ses conséquences restent de la responsabilité du lecteur et de son organisation.
Ressources
- Package ID prefix reservation : Microsoft Learn : critères et procédure de réservation de préfixe, ce que le badge garantit et ne garantit pas.
- Best practices for a secure software supply chain : Microsoft Learn : NuGetAudit, lock files, Package Source Mapping, signature. Couvre la surveillance post-intégration.
- Rechercher et évaluer des packages NuGet : Microsoft Learn : critères d'évaluation officiels. L'article prend le contre-pied de certains de ses raccourcis, sur les téléchargements et sur l'essai direct notamment.
- Package Source Mapping : Microsoft Learn : pertinent si un flux NuGet privé et nuget.org coexistent.
- Choose a License : implications des licences open source courantes (MIT, Apache, GPL et variantes).
- SPDX License List : identifiants normalisés, utile pour interpréter les licences affichées sur nuget.org.
-
NuGet Package Explorer : dépôt source, .NET Foundation
: inspection du contenu d'un
.nupkgsans installation, vérifications Source Link et build déterministe, détail des signatures. Version web sur nuget.info. - ILSpy : décompilateur .NET open source, pour l'audit binaire quand le code source n'est pas auditable.
-
NuGet Gallery : dépôt source, NuGet/Microsoft
: code source de la galerie nuget.org. Le
TyposquattingServicey est consultable ; l'algorithme de comparaison réellement utilisé en production n'y est pas inclus. - Template de revue de dépendance NuGet : Ordanche Solutions : template Markdown à copier dans une pull request pour documenter la décision.