Aller au contenu principal

NuGet : évaluer un package avant de l'intégrer

Trouver un package qui répond à un besoin est facile. Construire une opinion défendable sur sa fiabilité l'est moins. Une grille de signaux observables et un processus pour décider avant d'intégrer.

Le réflexe est naturel : avant d'implémenter une feature, chercher si un package NuGet ne le fait pas déjà. Un nom de package arrive (depuis une documentation, une recherche, une réponse d'agent), il correspond au besoin, et l'intégration suit. Ce moment, entre la découverte et l'intégration, est celui où un package conçu pour tromper passe le plus facilement : il n'a pas de CVE au moment de sa distribution, il n'apparaît dans aucun outil de scan, et son nom est choisi pour ne pas déclencher d'alerte.

Cet article ne couvre 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. Celle-ci sera traitée dans un futur article sur la gouvernance des dépendances. Il outille un seul moment : depuis la recherche d'un package jusqu'à 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 autorisées. Aucun n'évalue 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, qui se compte en jours sur les cas documentés, mais ne l'annule pas. Pendant cette fenêtre, l'évaluation au moment du choix est la seule barrière active côté développeur.

C'est cette lacune que la grille ci-dessous cherche à combler : les signaux observables sur nuget.org pour se faire 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 ne tranche seul : c'est leur lecture combinée, mise en regard du 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.

#SignalQuestion à se poser
1Le nomLe nom pourrait-il être confondu avec un package officiel ? Par quel chemin est-il arrivé ?
2Le publisher / ownersL'identité est-elle cohérente avec ce que le package prétend être ?
3Le badge Prefix ReservedLe package de référence le porte-t-il ? Le candidat l'a-t-il ?
4Vulnérabilité et versionLa page signale-t-elle une vulnérabilité ? La version visée est-elle la plus récente ?
5Le dépôt sourceLe dépôt est-il accessible, et le binaire publié en provient-il réellement ?
6La licenceEst-elle renseignée et compatible avec le contexte du projet ?
7La popularitéLa trajectoire des téléchargements est-elle cohérente avec l'histoire du package ?
8La signatureQui assume publiquement et de façon vérifiable la publication ?
9La maintenanceSi le mainteneur disparaît demain, quel est l'impact ?
10Les dépendancesQue 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.

Page nuget.org de Newtonsoft.Json 12.0.3 avec les signaux d'évaluation numérotés selon la grille
Page nuget.org de 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 détectables visuellement, à condition de connaître la nomenclature officielle du domaine. Le chemin par lequel le nom est arrivé conditionne donc la vigilance : un nom issu de la documentation officielle d'un projet n'est pas dans la même situation qu'un nom sorti des résultats de recherche nuget.org sur un terme fonctionnel, ou d'une source externe non vérifiée (un chat, un ticket, une réponse d'agent). Sur Acme.NetCore.Json, le nom est plausible pour un wrapper JSON : rien d'alarmant isolément, ce qui est précisément le piège.

L'attaque par homoglyphes, une variante 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 toutes les polices. 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 l'homoglyphe d'elle-même ; le copier-coller préserve la chaîne exacte, homoglyphe 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 serait attendu : tout octet au-delà de 7f sur un nom censé être latin est une anomalie immédiatement visible. Les éditeurs récents offrent un premier filet : VS Code souligne par défaut les caractères confusables avec l'ASCII (editor.unicodeHighlight.ambiguousCharacters), signal heuristique qui ne remplace pas le contrôle mais peut le déclencher plus tôt.

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.

La question : le nom pourrait-il être confondu avec un package officiel du domaine, et par quel chemin est-il arrivé ?

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, visibles 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, elle, reste 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 nombre et la nature de ces packages, 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. Mais rien n'empêche un compte nommé de façon visuellement proche d'un compte légitime (une lettre substituée, un suffixe ajouté), et le mécanisme documenté par nuget.org pour les litiges de nom est réactif, après création du compte. Un nom de publisher plausible pris seul est donc soumis au même type de doute qu'un nom de package pris seul.

La question : l'identité des owners est-elle cohérente avec ce que le package prétend être, et cette identité est-elle 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. 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 deux noms se présentent à é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 ne porte donc pas seulement sur le package, mais sur la version visée et l'existence d'un correctif.

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 ici : 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 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é

Mais un dépôt qui répond n'est pas une garantie : le champ est déclaratif, nuget.org ne vérifie pas que le package publié en provient. 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 :

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 déclarées par le client, modifiables avant envoi : les plateformes d'hébergement les acceptent sans validation. Ce qui est 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 prétend trois ans d'historique mais dont la première capture date de la semaine dernière pose une question concrète.

La question : 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) sont à résoudre avant l'intégration, indépendamment de la sécurité : Choose a License et la SPDX License List donnent les repères nécessaires. La question : 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 (cas du signal 1) démontre qu'aucun mécanisme côté nuget.org ne l'a empêché en pratique. Ce n'est donc pas un indicateur de confiance en soi, et il n'existe pas de seuil universel : la taille des domaines fonctionnels varie trop pour qu'un chiffre serve de référence. Ce qui reste exploitable, c'est la trajectoire du package comparée à sa propre histoire. L'onglet Versions affiche la répartition des téléchargements par version : une progression répartie dans le temps raconte une adoption réelle ; un volume concentré sur une version récente, en quelques jours, sans rapport avec le reste de l'historique, est le signal 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 pour les justifier.

Ce cas visait précisément le raccourci mental "beaucoup de téléchargements, donc adoption suffisante pour se dispenser d'une évaluation", un raccourci que la documentation officielle encourage en présentant les grands volumes comme la preuve que le package a fait ses preuves. La lecture de trajectoire est elle-même 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 se recoupe 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 propre du package. La question : cette trajectoire est-elle cohérente 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 est faible dans les deux sens : une signature ne garantit pas l'innocuité du code, et son absence n'est pas une preuve de malveillance. Sa valeur se limite à la traçabilité : un certificat rattaché à une organisation connue permet de vérifier qui a assumé publiquement la publication. Il pèse comme confirmation sur un package qui passe déjà les autres signaux, pas comme critère discriminant. La question : 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 prend le contrôle publie une version compromise en bénéficiant de toute la confiance accumulée par l'historique. Les signaux observables : date de la dernière release (onglet Versions), activité du dépôt, 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 du reste de l'écosystème. À l'inverse, un package trop récent pour avoir un historique exploitable est un signal en soi : si le besoin n'est pas urgent, différer l'intégration de quelques semaines est une réponse légitime. La question : si le mainteneur disparaît demain, quel est l'impact pour le projet, et ce risque est-il acceptable compte tenu 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 tout le graphe transitif, qui peut être large et profond, 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 regard, 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 :

# Graphe complet, 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>

La question : 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, elle 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 : le moyen le plus direct de voir une cible MSBuild avant qu'elle ne s'exécute.

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 affichées par l'outil lui-même : 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 pose que la meilleure façon d'évaluer un package est de l'essayer, et propose les signaux de la page nuget.org comme un substitut plus rapide. Le processus ci-dessous retient la même conclusion pratique (la page d'abord) pour une raison différente : l'essai suppose un package de bonne foi, ce que l'évaluation cherche justement à établir. Un package peut embarquer des cibles MSBuild importées automatiquement à son ajout et exécutées à la première compilation : essayer un package malveillant, c'est déjà exécuter son code. L'essai vient 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.

  1. 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".
  2. Vérifier que c'est une chaîne ASCII. [1] Inspection des octets avec hexdump -C ou Format-Hex.
  3. 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.
  4. 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.
  5. É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.
  6. 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-transitive confirme l'absence de vulnérabilité connue dans le graphe.

La bonne question n'est pas "est-ce dangereux ?" mais "suis-je en mesure de défendre cette intégration si elle est questionnée 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 faire la différence entre deux profils aux signaux faibles. Les deux packages ci-dessous sont synthétiques : les noms, chiffres et URLs sont fictifs mais représentatifs de profils rencontrés sur nuget.org. Ce choix est délibéré : les packages malveillants documentés ont tous été retirés et ne sont plus vérifiables, et utiliser 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, et 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 : un homoglyphe confirmé, un pic soudain de téléchargements artificiels, du 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. Et suivant 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, pas suffisante : un package sain à l'intégration peut devenir problématique après, et la surveillance dans le temps relève d'une démarche distincte.

Ce que la démarche cherche à produire n'est pas 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 : pas une garantie d'innocuité, mais la trace d'une démarche 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

Vous souhaitez faire monter en compétence vos développeurs ?

Je propose des formations techniques et de l'accompagnement de projets.

Discuter de votre besoin

Articles connexes

Attaques supply chain sur NuGet : une analyse de risque

Nom, popularité, dépôt, mainteneur, ancienneté : chaque indicateur de confiance instinctif a fait l'objet d'une falsification documentée sur NuGet. Analyse de risque structurée sur la méthode EBIOS RM, cas documentés à l'appui.