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
| Metrique | Valeur |
|---|---|
| Wild TPR global | 92.5% (13 486 / 14 587) |
| compromised_lib | 97.8% (904 / 924) |
| malicious_intent | 92.1% (12 582 / 13 663) |
| Erreurs | 0 |
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
| Score | Packages | Interpretation |
|---|---|---|
| 0 | 1 101 | Non detectes (aucune menace trouvee) |
| 1-9 | 2 488 | Signaux faibles, sous le seuil |
| 10-24 | 2 125 | Zone grise (seuil standard = 20) |
| 25-49 | 4 900 | Detectes avec confiance moderee |
| 50-74 | 1 527 | Detectes avec haute confiance |
| 75-100 | 2 446 | Detectes 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 marquescompromised_libdans 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 :
| Compound | Composants |
|---|---|
| crypto_staged_payload | staged_binary_payload + crypto_decipher |
| lifecycle_typosquat | lifecycle_script + typosquat_detected |
| lifecycle_inline_exec | lifecycle_script + node_inline_exec |
| lifecycle_remote_require | lifecycle_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
| Metrique | Interne | Wild (Datadog) |
|---|---|---|
| TPR | 93.9% (46/49) | 92.5% (13 486/14 587) |
| ADR | 96.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.