← Blog

Nos metriques internes (TPR sur 49 samples, ADR sur 107 adversariaux) mesurent la precision sur des echantillons choisis. Mais la vraie question est : que se passe-t-il sur 17 000 malwares reels, en conditions sauvages ?

Le dataset Datadog Security Labs contient 17 922 packages npm confirmes malveillants. On les a tous scannes.

Le setup

Execution sur VPS. 17 922 packages, chacun telecharge, extrait, et scanne avec les 14 scanners. Temps total : 32 141 secondes (~9 heures). Zero erreur.

Sur les 17 922 packages :

  • 3 335 skips - packages sans fichiers JavaScript (binaires purs, assets, packages vides). Exclus du calcul.
  • 14 587 in-scope - packages avec du code JavaScript analysable

Les resultats

MetriqueValeur
Wild TPR global92.5% (13 486 / 14 587)
compromised_lib97.8% (904 / 924)
malicious_intent92.1% (12 582 / 13 663)
Erreurs0

La distinction compromised_lib vs malicious_intent est importante. Les compromised_lib sont des packages legitimes dont une version specifique a ete compromisee (pattern ua-parser-js, event-stream). Les malicious_intent sont des packages crees avec l'intention de nuire (typosquats, droppers, exfiltrators). MUAD'DIB detecte mieux les compromissions (97.8%) car elles laissent plus de traces dans le diff entre versions.

Distribution des scores

ScorePackagesInterpretation
01 101Non detectes (aucune menace trouvee)
1-92 488Signaux faibles, sous le seuil
10-242 125Zone grise (seuil standard = 20)
25-494 900Detectes avec confiance moderee
50-741 527Detectes avec haute confiance
75-1002 446Detectes avec tres haute confiance

La majorite des detections (8 873 packages, 61%) ont un score >= 25. Ce n'est pas du scoring marginal - ce sont des detections claires.

Les MISS : qu'est-ce qu'on rate ?

1 101 packages avec score 0 et 0 menaces. Analyse des causes :

  • @react-native-aria/* - Packages marques compromised_lib dans le dataset Datadog, mais sans code JS malveillant detectable statiquement. La compromission est au niveau du registre/maintainer, pas du code source.
  • xrpl - Bibliotheque crypto legitime dont des versions specifiques ont ete compromisees. Le code malveillant a ete injecte via un processus de build, pas directement dans les sources.
  • Packages sans code - Certains packages ne contiennent que des fichiers de configuration ou des assets. Aucun code a analyser = aucune detection possible.

Ces MISS sont coherents avec les limites connues de l'analyse statique : si le code malveillant n'est pas dans les sources scannees (build-time injection, registre compromis, binaires pre-compiles), un scanner statique ne peut pas le detecter.

Le role des compound rules

Avant les compound rules (v2.9.2), le Wild TPR estime etait autour de ~88%. Le gap de ~4.5% a ete comble par 6 regles de scoring compose :

CompoundComposants
crypto_staged_payloadstaged_binary_payload + crypto_decipher
lifecycle_typosquatlifecycle_script + typosquat_detected
lifecycle_inline_execlifecycle_script + node_inline_exec
lifecycle_remote_requirelifecycle_script + network_require

Ces combinaisons n'apparaissent jamais dans les 529 packages benins du dataset de reference. Un package avec un script lifecycle ET un nom typosquat est toujours malveillant. Un script lifecycle qui fait require('https') aussi.

Comparaison avec les metriques internes

MetriqueInterneWild (Datadog)
TPR93.9% (46/49)92.5% (13 486/14 587)
ADR96.3% (103/107)-
compromised_lib-97.8%

Les metriques internes et sauvages convergent (~93% vs ~92.5%). C'est un bon signe : le ground truth de 49 samples et les 107 adversariaux ne sont pas sur-ajustes. La performance generalise au-dela du dataset de developpement.

Lecon

Un benchmark sur 17K packages reels ne ment pas. Les metriques internes sur 49+107 echantillons etaient honnetes - la performance sauvage le confirme. Mais le benchmark revele aussi les limites structurelles de l'analyse statique : les compromissions build-time, les injections registre, et les binaires pre-compiles restent hors de portee.

92.5% n'est pas 100%. Les 7.5% restants sont un rappel que la detection statique est une couche de defense, pas la seule.