muaddib-scanner 1.8.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.fr.md CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  Les attaques supply-chain npm et PyPI explosent. Shai-Hulud a compromis 25K+ repos en 2025. Les outils existants détectent, mais n'aident pas à répondre.
32
32
 
33
- MUAD'DIB combine analyse statique + analyse dynamique (sandbox Docker) pour détecter les menaces ET guider votre réponse.
33
+ MUAD'DIB combine analyse statique + analyse dynamique (sandbox Docker) + **détection comportementale d'anomalies** (v2.0) pour détecter les menaces ET guider votre réponse — même avant leur apparition dans une base d'IOC.
34
34
 
35
35
  ---
36
36
 
@@ -392,6 +392,119 @@ Détecte les patterns malveillants dans les fichiers YAML `.github/workflows/`,
392
392
  | Supply chain compromise | T1195.002 | IOC matching |
393
393
  | Package PyPI malveillant | T1195.002 | IOC matching |
394
394
  | Sandbox analyse dynamique | Multiple | Docker + strace + tcpdump |
395
+ | Ajout soudain de script lifecycle | T1195.002 | Analyse temporelle |
396
+ | Injection d'API dangereuse entre versions | T1195.002 | Diff AST temporel |
397
+ | Anomalie de fréquence de publication | T1195.002 | Métadonnées registre |
398
+ | Changement de maintainer/publisher | T1195.002 | Métadonnées registre |
399
+ | Exfiltration de canary tokens | T1552.001 | Honey tokens sandbox |
400
+
401
+ ---
402
+
403
+ ## Détection d'anomalies supply chain (v2.0)
404
+
405
+ MUAD'DIB 2.0 introduit un changement de paradigme : de la **détection par IOC** (réactive, nécessite des menaces connues) à la **détection comportementale d'anomalies** (proactive, détecte les menaces inconnues en repérant les changements suspects).
406
+
407
+ Les scanners supply-chain traditionnels reposent sur des listes de packages malveillants connus. Le problème : ils ne détectent les menaces qu'APRÈS leur identification et signalement. Des attaques comme **ua-parser-js** (2021), **event-stream** (2018) et **Shai-Hulud** (2025) sont passées inaperçues pendant des heures ou des jours car aucun IOC n'existait encore.
408
+
409
+ MUAD'DIB 2.0 ajoute 5 features de détection comportementale capables d'attraper ces attaques **avant** leur apparition dans une base d'IOC, en analysant ce qui a changé entre les versions d'un package.
410
+
411
+ ### Nouvelles features
412
+
413
+ #### 1. Détection soudaine de scripts lifecycle (`--temporal`)
414
+
415
+ Détecte quand des scripts `preinstall`, `install` ou `postinstall` apparaissent soudainement dans une nouvelle version d'un package qui n'en avait jamais. C'est le vecteur d'attaque #1 des attaques supply-chain.
416
+
417
+ ```bash
418
+ muaddib scan . --temporal
419
+ ```
420
+
421
+ #### 2. Diff AST temporel (`--temporal-ast`)
422
+
423
+ Télécharge les deux dernières versions de chaque dépendance et compare leur AST (Abstract Syntax Tree) pour détecter les APIs dangereuses nouvellement ajoutées : `child_process`, `eval`, `Function`, `net.connect`, `process.env`, `fetch`, etc.
424
+
425
+ ```bash
426
+ muaddib scan . --temporal-ast
427
+ ```
428
+
429
+ #### 3. Anomalie de fréquence de publication (`--temporal-publish`)
430
+
431
+ Détecte les patterns de publication anormaux : rafale de versions en 24h, package dormant soudainement mis à jour après 6+ mois, succession rapide de versions (plusieurs releases en moins d'1h).
432
+
433
+ ```bash
434
+ muaddib scan . --temporal-publish
435
+ ```
436
+
437
+ #### 4. Détection de changement de maintainer (`--temporal-maintainer`)
438
+
439
+ Détecte les changements de maintainers entre versions : nouveau maintainer ajouté, seul maintainer remplacé (pattern event-stream), noms de maintainers suspects, nouveau publisher.
440
+
441
+ ```bash
442
+ muaddib scan . --temporal-maintainer
443
+ ```
444
+
445
+ #### 5. Canary Tokens / Honey Tokens (sandbox)
446
+
447
+ Injecte de faux credentials (GITHUB_TOKEN, NPM_TOKEN, clés AWS) dans l'environnement sandbox avant d'installer un package. Si le package tente d'exfiltrer ces honey tokens via HTTP, DNS ou stdout, il est signalé comme malveillant confirmé.
448
+
449
+ ```bash
450
+ muaddib sandbox suspicious-package
451
+ ```
452
+
453
+ ### Scan temporel complet
454
+
455
+ Activer toutes les features d'analyse temporelle en une commande :
456
+
457
+ ```bash
458
+ muaddib scan . --temporal-full
459
+ ```
460
+
461
+ ### Exemples d'utilisation
462
+
463
+ ```bash
464
+ # Scan comportemental complet (5 features)
465
+ muaddib scan . --temporal-full
466
+
467
+ # Détection lifecycle scripts uniquement
468
+ muaddib scan . --temporal
469
+
470
+ # Diff AST + changement maintainer
471
+ muaddib scan . --temporal-ast --temporal-maintainer
472
+
473
+ # Sandbox avec canary tokens (activé par défaut)
474
+ muaddib sandbox suspicious-package
475
+
476
+ # Sandbox sans canary tokens
477
+ muaddib sandbox suspicious-package --no-canary
478
+ ```
479
+
480
+ ### Nouvelles règles de détection (v2.0)
481
+
482
+ | Rule ID | Nom | Sévérité | Feature |
483
+ |---------|-----|----------|---------|
484
+ | MUADDIB-TEMPORAL-001 | Ajout soudain de script lifecycle (Critique) | CRITICAL | `--temporal` |
485
+ | MUADDIB-TEMPORAL-002 | Ajout soudain de script lifecycle | HIGH | `--temporal` |
486
+ | MUADDIB-TEMPORAL-003 | Script lifecycle modifié | MEDIUM | `--temporal` |
487
+ | MUADDIB-TEMPORAL-AST-001 | API dangereuse ajoutée (Critique) | CRITICAL | `--temporal-ast` |
488
+ | MUADDIB-TEMPORAL-AST-002 | API dangereuse ajoutée (High) | HIGH | `--temporal-ast` |
489
+ | MUADDIB-TEMPORAL-AST-003 | API dangereuse ajoutée (Medium) | MEDIUM | `--temporal-ast` |
490
+ | MUADDIB-PUBLISH-001 | Rafale de publications détectée | HIGH | `--temporal-publish` |
491
+ | MUADDIB-PUBLISH-002 | Pic de package dormant | HIGH | `--temporal-publish` |
492
+ | MUADDIB-PUBLISH-003 | Succession rapide de versions | MEDIUM | `--temporal-publish` |
493
+ | MUADDIB-MAINTAINER-001 | Nouveau maintainer ajouté | HIGH | `--temporal-maintainer` |
494
+ | MUADDIB-MAINTAINER-002 | Maintainer suspect détecté | CRITICAL | `--temporal-maintainer` |
495
+ | MUADDIB-MAINTAINER-003 | Seul maintainer changé | HIGH | `--temporal-maintainer` |
496
+ | MUADDIB-MAINTAINER-004 | Nouveau publisher détecté | MEDIUM | `--temporal-maintainer` |
497
+ | MUADDIB-CANARY-001 | Exfiltration de canary token | CRITICAL | sandbox |
498
+
499
+ ### Pourquoi c'est important
500
+
501
+ Ces features détectent des attaques comme :
502
+ - **Shai-Hulud** (2025) : Détecté par temporal lifecycle + AST diff (ajout soudain de `postinstall` + `child_process`)
503
+ - **ua-parser-js** (2021) : Détecté par changement maintainer + détection lifecycle
504
+ - **event-stream** (2018) : Détecté par changement de seul maintainer + AST diff (nouvelle dépendance `flatmap-stream` avec `eval`)
505
+ - **coa/rc** (2021) : Détecté par rafale de publications + détection lifecycle
506
+
507
+ Le tout sans avoir besoin d'un seul IOC.
395
508
 
396
509
  ---
397
510
 
@@ -488,7 +601,7 @@ Les alertes apparaissent dans Security > Code scanning alerts.
488
601
  ## Architecture
489
602
 
490
603
  ```
491
- MUAD'DIB Scanner
604
+ MUAD'DIB 2.0 Scanner
492
605
  |
493
606
  +-- IOC Match (225 000+ packages, JSON DB)
494
607
  | +-- OSV.dev npm dump (200K+ entrées MAL-*)
@@ -500,14 +613,24 @@ MUAD'DIB Scanner
500
613
  | +-- Snyk Known Malware
501
614
  | +-- Static IOCs (Socket, Phylum)
502
615
  |
503
- +-- AST Parse (acorn)
504
- +-- Pattern Matching (shell, scripts)
505
- +-- Typosquat Detection (npm + PyPI, Levenshtein)
506
- +-- Python Scanner (requirements.txt, setup.py, pyproject.toml)
507
- +-- Analyse Entropie Shannon
508
- +-- GitHub Actions Scanner
616
+ +-- 12 Scanners Parallèles
617
+ | +-- AST Parse (acorn)
618
+ | +-- Pattern Matching (shell, scripts)
619
+ | +-- Typosquat Detection (npm + PyPI, Levenshtein)
620
+ | +-- Python Scanner (requirements.txt, setup.py, pyproject.toml)
621
+ | +-- Analyse Entropie Shannon
622
+ | +-- GitHub Actions Scanner
623
+ | +-- Package, Dependencies, Hash, npm-registry, Dataflow scanners
624
+ |
625
+ +-- Détection d'Anomalies Supply Chain (v2.0)
626
+ | +-- Détection Lifecycle Script Temporelle (--temporal)
627
+ | +-- Diff AST Temporel (--temporal-ast)
628
+ | +-- Anomalie Fréquence de Publication (--temporal-publish)
629
+ | +-- Détection Changement Maintainer (--temporal-maintainer)
630
+ | +-- Canary Tokens / Honey Tokens (sandbox)
631
+ |
509
632
  +-- Paranoid Mode (ultra-strict)
510
- +-- Docker Sandbox (behavioral analysis, network capture)
633
+ +-- Docker Sandbox (analyse comportementale, capture réseau, canary tokens)
511
634
  +-- Moniteur Zero-Day (polling RSS npm + PyPI, alertes Discord, rapport quotidien)
512
635
  |
513
636
  v
@@ -552,7 +675,7 @@ npm test
552
675
 
553
676
  ### Tests
554
677
 
555
- - **326 tests unitaires/intégration** - 80% coverage via [Codecov](https://codecov.io/gh/DNSZLSK/muad-dib)
678
+ - **541 tests unitaires/intégration** - 80% coverage via [Codecov](https://codecov.io/gh/DNSZLSK/muad-dib)
556
679
  - **56 tests de fuzzing** - YAML malformé, JSON invalide, fichiers binaires, ReDoS, unicode, inputs 10MB
557
680
  - **15 tests adversariaux** - Packages malveillants simulés, taux de détection 15/15
558
681
  - **8 tests multi-facteur typosquat** - Cas limites et comportement cache
package/README.md CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  npm and PyPI supply-chain attacks are exploding. Shai-Hulud compromised 25K+ repos in 2025. Existing tools detect threats but don't help you respond.
32
32
 
33
- MUAD'DIB combines static analysis + dynamic analysis (Docker sandbox) to detect threats AND guide your response.
33
+ MUAD'DIB combines static analysis + dynamic analysis (Docker sandbox) + **behavioral anomaly detection** (v2.0) to detect threats AND guide your response — even before they appear in any IOC database.
34
34
 
35
35
  ---
36
36
 
@@ -393,6 +393,119 @@ Detects malicious patterns in `.github/workflows/` YAML files, including Shai-Hu
393
393
  | Supply chain compromise | T1195.002 | IOC matching |
394
394
  | PyPI malicious package | T1195.002 | IOC matching |
395
395
  | Sandbox dynamic analysis | Multiple | Docker + strace + tcpdump |
396
+ | Sudden lifecycle script addition | T1195.002 | Temporal analysis |
397
+ | Dangerous API injection between versions | T1195.002 | Temporal AST diff |
398
+ | Publish frequency anomaly | T1195.002 | Registry metadata |
399
+ | Maintainer/publisher change | T1195.002 | Registry metadata |
400
+ | Canary token exfiltration | T1552.001 | Sandbox honey tokens |
401
+
402
+ ---
403
+
404
+ ## Supply Chain Anomaly Detection (v2.0)
405
+
406
+ MUAD'DIB 2.0 introduces a paradigm shift: from **IOC-based detection** (reactive, requires known threats) to **behavioral anomaly detection** (proactive, detects unknown threats by spotting suspicious changes).
407
+
408
+ Traditional supply-chain scanners rely on blocklists of known malicious packages. The problem: they can only detect threats AFTER they've been identified and reported. Attacks like **ua-parser-js** (2021), **event-stream** (2018), and **Shai-Hulud** (2025) went undetected for hours or days because no IOC existed yet.
409
+
410
+ MUAD'DIB 2.0 adds 5 behavioral detection features that can catch these attacks **before** they appear in any IOC database, by analyzing what changed between package versions.
411
+
412
+ ### New features
413
+
414
+ #### 1. Sudden Lifecycle Script Detection (`--temporal`)
415
+
416
+ Detects when `preinstall`, `install`, or `postinstall` scripts suddenly appear in a new version of a package that never had them before. This is the #1 attack vector for supply-chain attacks.
417
+
418
+ ```bash
419
+ muaddib scan . --temporal
420
+ ```
421
+
422
+ #### 2. Temporal AST Diff (`--temporal-ast`)
423
+
424
+ Downloads the two latest versions of each dependency and compares their AST (Abstract Syntax Tree) to detect newly added dangerous APIs: `child_process`, `eval`, `Function`, `net.connect`, `process.env`, `fetch`, etc.
425
+
426
+ ```bash
427
+ muaddib scan . --temporal-ast
428
+ ```
429
+
430
+ #### 3. Publish Frequency Anomaly (`--temporal-publish`)
431
+
432
+ Detects abnormal publishing patterns: burst of versions in 24h, dormant package suddenly updated after 6+ months, rapid version succession (multiple releases in under 1h).
433
+
434
+ ```bash
435
+ muaddib scan . --temporal-publish
436
+ ```
437
+
438
+ #### 4. Maintainer Change Detection (`--temporal-maintainer`)
439
+
440
+ Detects changes in package maintainers between versions: new maintainer added, sole maintainer replaced (event-stream pattern), suspicious maintainer names, new publisher.
441
+
442
+ ```bash
443
+ muaddib scan . --temporal-maintainer
444
+ ```
445
+
446
+ #### 5. Canary Tokens / Honey Tokens (sandbox)
447
+
448
+ Injects fake credentials (GITHUB_TOKEN, NPM_TOKEN, AWS keys) into the sandbox environment before installing a package. If the package attempts to exfiltrate these honey tokens via HTTP, DNS, or stdout, it's flagged as confirmed malicious.
449
+
450
+ ```bash
451
+ muaddib sandbox suspicious-package
452
+ ```
453
+
454
+ ### Full temporal scan
455
+
456
+ Enable all temporal analysis features at once:
457
+
458
+ ```bash
459
+ muaddib scan . --temporal-full
460
+ ```
461
+
462
+ ### Usage examples
463
+
464
+ ```bash
465
+ # Full behavioral scan (all 5 features)
466
+ muaddib scan . --temporal-full
467
+
468
+ # Only lifecycle script detection
469
+ muaddib scan . --temporal
470
+
471
+ # AST diff + maintainer change
472
+ muaddib scan . --temporal-ast --temporal-maintainer
473
+
474
+ # Sandbox with canary tokens (enabled by default)
475
+ muaddib sandbox suspicious-package
476
+
477
+ # Sandbox without canary tokens
478
+ muaddib sandbox suspicious-package --no-canary
479
+ ```
480
+
481
+ ### New detection rules (v2.0)
482
+
483
+ | Rule ID | Name | Severity | Feature |
484
+ |---------|------|----------|---------|
485
+ | MUADDIB-TEMPORAL-001 | Sudden Lifecycle Script Added (Critical) | CRITICAL | `--temporal` |
486
+ | MUADDIB-TEMPORAL-002 | Sudden Lifecycle Script Added | HIGH | `--temporal` |
487
+ | MUADDIB-TEMPORAL-003 | Lifecycle Script Modified | MEDIUM | `--temporal` |
488
+ | MUADDIB-TEMPORAL-AST-001 | Dangerous API Added (Critical) | CRITICAL | `--temporal-ast` |
489
+ | MUADDIB-TEMPORAL-AST-002 | Dangerous API Added (High) | HIGH | `--temporal-ast` |
490
+ | MUADDIB-TEMPORAL-AST-003 | Dangerous API Added (Medium) | MEDIUM | `--temporal-ast` |
491
+ | MUADDIB-PUBLISH-001 | Publish Burst Detected | HIGH | `--temporal-publish` |
492
+ | MUADDIB-PUBLISH-002 | Dormant Package Spike | HIGH | `--temporal-publish` |
493
+ | MUADDIB-PUBLISH-003 | Rapid Version Succession | MEDIUM | `--temporal-publish` |
494
+ | MUADDIB-MAINTAINER-001 | New Maintainer Added | HIGH | `--temporal-maintainer` |
495
+ | MUADDIB-MAINTAINER-002 | Suspicious Maintainer Detected | CRITICAL | `--temporal-maintainer` |
496
+ | MUADDIB-MAINTAINER-003 | Sole Maintainer Changed | HIGH | `--temporal-maintainer` |
497
+ | MUADDIB-MAINTAINER-004 | New Publisher Detected | MEDIUM | `--temporal-maintainer` |
498
+ | MUADDIB-CANARY-001 | Canary Token Exfiltration | CRITICAL | sandbox |
499
+
500
+ ### Why it matters
501
+
502
+ These features detect attacks like:
503
+ - **Shai-Hulud** (2025): Would be caught by temporal lifecycle + AST diff (sudden `postinstall` + `child_process` added)
504
+ - **ua-parser-js** (2021): Would be caught by maintainer change + lifecycle script detection
505
+ - **event-stream** (2018): Would be caught by sole maintainer change + AST diff (new `flatmap-stream` dependency with `eval`)
506
+ - **coa/rc** (2021): Would be caught by publish burst + lifecycle script detection
507
+
508
+ All without needing a single IOC entry.
396
509
 
397
510
  ---
398
511
 
@@ -489,7 +602,7 @@ Alerts appear in Security > Code scanning alerts.
489
602
  ## Architecture
490
603
 
491
604
  ```
492
- MUAD'DIB Scanner
605
+ MUAD'DIB 2.0 Scanner
493
606
  |
494
607
  +-- IOC Match (225,000+ packages, JSON DB)
495
608
  | +-- OSV.dev npm dump (200K+ MAL-* entries)
@@ -512,8 +625,15 @@ MUAD'DIB Scanner
512
625
  | +-- GitHub Actions Scanner
513
626
  | +-- Package, Dependencies, Hash, npm-registry, Dataflow scanners
514
627
  |
628
+ +-- Supply Chain Anomaly Detection (v2.0)
629
+ | +-- Temporal Lifecycle Script Detection (--temporal)
630
+ | +-- Temporal AST Diff (--temporal-ast)
631
+ | +-- Publish Frequency Anomaly (--temporal-publish)
632
+ | +-- Maintainer Change Detection (--temporal-maintainer)
633
+ | +-- Canary Tokens / Honey Tokens (sandbox)
634
+ |
515
635
  +-- Paranoid Mode (ultra-strict)
516
- +-- Docker Sandbox (behavioral analysis, network capture)
636
+ +-- Docker Sandbox (behavioral analysis, network capture, canary tokens)
517
637
  +-- Zero-Day Monitor (npm + PyPI RSS polling, Discord alerts, daily report)
518
638
  |
519
639
  v
@@ -558,7 +678,7 @@ npm test
558
678
 
559
679
  ### Testing
560
680
 
561
- - **326 unit/integration tests** - 80% code coverage via [Codecov](https://codecov.io/gh/DNSZLSK/muad-dib)
681
+ - **541 unit/integration tests** - 80% code coverage via [Codecov](https://codecov.io/gh/DNSZLSK/muad-dib)
562
682
  - **56 fuzz tests** - Malformed YAML, invalid JSON, binary files, ReDoS, unicode, 10MB inputs
563
683
  - **15 adversarial tests** - Simulated malicious packages, 15/15 detection rate
564
684
  - **8 multi-factor typosquat tests** - Edge cases and cache behavior
package/bin/muaddib.js CHANGED
@@ -25,6 +25,11 @@ let webhookUrl = null;
25
25
  let paranoidMode = false;
26
26
  let excludeDirs = [];
27
27
  let entropyThreshold = null;
28
+ let temporalMode = false;
29
+ let temporalAstMode = false;
30
+ let temporalPublishMode = false;
31
+ let temporalMaintainerMode = false;
32
+ let temporalFullMode = false;
28
33
 
29
34
  for (let i = 0; i < options.length; i++) {
30
35
  if (options[i] === '--json') {
@@ -90,8 +95,20 @@ for (let i = 0; i < options.length; i++) {
90
95
  i++;
91
96
  } else if (options[i] === '--paranoid') {
92
97
  paranoidMode = true;
98
+ } else if (options[i] === '--temporal-full') {
99
+ temporalFullMode = true;
100
+ } else if (options[i] === '--temporal-ast') {
101
+ temporalAstMode = true;
102
+ } else if (options[i] === '--temporal-publish') {
103
+ temporalPublishMode = true;
104
+ } else if (options[i] === '--temporal-maintainer') {
105
+ temporalMaintainerMode = true;
106
+ } else if (options[i] === '--temporal') {
107
+ temporalMode = true;
93
108
  } else if (options[i] === '--strict') {
94
109
  // Sandbox strict mode flag (parsed here, used by sandbox commands)
110
+ } else if (options[i] === '--no-canary') {
111
+ // Sandbox canary disable flag (parsed here, used by sandbox commands)
95
112
  } else if (!options[i].startsWith('-')) {
96
113
  target = options[i];
97
114
  }
@@ -301,7 +318,7 @@ const helpText = `
301
318
  muaddib remove-hooks [path] Remove MUAD'DIB git hooks
302
319
  muaddib update Update IOCs
303
320
  muaddib scrape Scrape new IOCs
304
- muaddib sandbox <pkg> [--strict] Analyze in isolated Docker container
321
+ muaddib sandbox <pkg> [--strict] [--no-canary] Analyze in isolated Docker container
305
322
  muaddib sandbox-report <pkg> Sandbox + detailed network report
306
323
  muaddib version Show version
307
324
 
@@ -323,6 +340,12 @@ const helpText = `
323
340
  --fail-on [level] Fail level (critical|high|medium|low)
324
341
  --webhook [url] Discord/Slack webhook
325
342
  --paranoid Ultra-strict mode
343
+ --temporal Detect sudden lifecycle script changes (network requests per package)
344
+ --temporal-ast Detect sudden dangerous API additions via AST diff (downloads tarballs)
345
+ --temporal-publish Detect publish frequency anomalies (bursts, dormant spikes)
346
+ --temporal-maintainer Detect maintainer changes (new maintainer, account takeover)
347
+ --temporal-full All temporal analyses (lifecycle + AST + publish + maintainer)
348
+ --no-canary Disable honey token injection in sandbox
326
349
  --exclude [dir] Exclude directory from scan (repeatable)
327
350
  --entropy-threshold [n] Custom string-level entropy threshold (default: 5.5)
328
351
  --save-dev, -D Install as dev dependency
@@ -353,6 +376,10 @@ if (command === 'version' || command === '--version' || command === '-v') {
353
376
  failLevel: failLevel,
354
377
  webhook: webhookUrl,
355
378
  paranoid: paranoidMode,
379
+ temporal: temporalMode || temporalFullMode,
380
+ temporalAst: temporalAstMode || temporalFullMode,
381
+ temporalPublish: temporalPublishMode || temporalFullMode,
382
+ temporalMaintainer: temporalMaintainerMode || temporalFullMode,
356
383
  exclude: excludeDirs,
357
384
  entropyThreshold: entropyThreshold
358
385
  }).then(exitCode => {
@@ -378,6 +405,92 @@ if (command === 'version' || command === '--version' || command === '-v') {
378
405
  console.error('[ERROR]', err.message);
379
406
  process.exit(1);
380
407
  });
408
+ } else if (command === 'monitor') {
409
+ const testPkg = options.filter(o => !o.startsWith('-'));
410
+ const isTemporal = options.includes('--temporal');
411
+ const isTemporalAst = options.includes('--temporal-ast');
412
+ const isTest = options.includes('--test');
413
+
414
+ if (isTemporalAst && isTest) {
415
+ const actualPkg = options.filter(o => !o.startsWith('-')).pop();
416
+ if (!actualPkg) {
417
+ console.log('Usage: muaddib monitor --temporal-ast --test <package-name>');
418
+ process.exit(1);
419
+ }
420
+ const { detectSuddenAstChanges } = require('../src/temporal-ast-diff.js');
421
+ console.log(`[TEMPORAL-AST] Analyzing ${actualPkg}...\n`);
422
+ detectSuddenAstChanges(actualPkg).then(result => {
423
+ console.log(`Package: ${result.packageName}`);
424
+ console.log(`Latest version: ${result.latestVersion || 'N/A'}`);
425
+ console.log(`Previous version: ${result.previousVersion || 'N/A'}`);
426
+ console.log(`Suspicious: ${result.suspicious ? 'YES' : 'NO'}`);
427
+ if (result.metadata.latestPublishedAt) {
428
+ console.log(`Published: ${result.metadata.latestPublishedAt}`);
429
+ }
430
+ if (result.findings.length > 0) {
431
+ console.log(`\nFindings:`);
432
+ for (const f of result.findings) {
433
+ console.log(` [${f.severity}] ${f.pattern}: ${f.description}`);
434
+ }
435
+ } else {
436
+ console.log(`\nNo dangerous API changes detected between the last two versions.`);
437
+ }
438
+ process.exit(result.suspicious ? 1 : 0);
439
+ }).catch(err => {
440
+ console.error(`[ERROR] ${err.message}`);
441
+ process.exit(1);
442
+ });
443
+ } else if (isTemporal && isTest && testPkg.length > 0) {
444
+ const { detectSuddenLifecycleChange } = require('../src/temporal-analysis.js');
445
+ const pkgName = testPkg[testPkg.indexOf('--test') !== -1 ? testPkg.length - 1 : 0] || testPkg[0];
446
+ // Find the package name: it's the non-flag argument
447
+ const actualPkg = options.filter(o => !o.startsWith('-')).pop();
448
+ if (!actualPkg) {
449
+ console.log('Usage: muaddib monitor --temporal --test <package-name>');
450
+ process.exit(1);
451
+ }
452
+ console.log(`[TEMPORAL] Analyzing ${actualPkg}...\n`);
453
+ detectSuddenLifecycleChange(actualPkg).then(result => {
454
+ console.log(`Package: ${result.packageName}`);
455
+ console.log(`Latest version: ${result.latestVersion || 'N/A'}`);
456
+ console.log(`Previous version: ${result.previousVersion || 'N/A'}`);
457
+ console.log(`Suspicious: ${result.suspicious ? 'YES' : 'NO'}`);
458
+ if (result.metadata.note) {
459
+ console.log(`Note: ${result.metadata.note}`);
460
+ }
461
+ if (result.metadata.latestPublishedAt) {
462
+ console.log(`Published: ${result.metadata.latestPublishedAt}`);
463
+ }
464
+ if (result.metadata.maintainers && result.metadata.maintainers.length > 0) {
465
+ const names = result.metadata.maintainers.map(m => m.name || m.email).join(', ');
466
+ console.log(`Maintainers: ${names}`);
467
+ }
468
+ if (result.findings.length > 0) {
469
+ console.log(`\nFindings:`);
470
+ for (const f of result.findings) {
471
+ const action = f.type === 'lifecycle_added' ? 'ADDED' : f.type === 'lifecycle_modified' ? 'MODIFIED' : 'REMOVED';
472
+ const value = f.type === 'lifecycle_modified' ? f.newValue : f.value;
473
+ console.log(` [${f.severity}] ${f.script} script ${action}: "${value}"`);
474
+ }
475
+ } else {
476
+ console.log(`\nNo lifecycle script changes detected between the last two versions.`);
477
+ }
478
+ process.exit(result.suspicious ? 1 : 0);
479
+ }).catch(err => {
480
+ console.error(`[ERROR] ${err.message}`);
481
+ process.exit(1);
482
+ });
483
+ } else if (isTemporal && isTest) {
484
+ console.log('Usage: muaddib monitor --temporal --test <package-name>');
485
+ process.exit(1);
486
+ } else {
487
+ // Start full monitor
488
+ const { startMonitor } = require('../src/monitor.js');
489
+ startMonitor().catch(err => {
490
+ console.error('[ERROR]', err.message);
491
+ process.exit(1);
492
+ });
493
+ }
381
494
  } else if (command === 'daemon') {
382
495
  startDaemon({ webhook: webhookUrl });
383
496
  } else if (command === 'install' || command === 'i') {
@@ -404,13 +517,14 @@ if (command === 'version' || command === '--version' || command === '-v') {
404
517
  const sandboxOpts = options.filter(o => !o.startsWith('-'));
405
518
  const packageName = sandboxOpts[0];
406
519
  const strict = options.includes('--strict');
520
+ const canary = !options.includes('--no-canary');
407
521
  if (!packageName) {
408
- console.log('Usage: muaddib sandbox <package-name> [--strict]');
522
+ console.log('Usage: muaddib sandbox <package-name> [--strict] [--no-canary]');
409
523
  process.exit(1);
410
524
  }
411
525
 
412
526
  buildSandboxImage()
413
- .then(() => runSandbox(packageName, { strict }))
527
+ .then(() => runSandbox(packageName, { strict, canary }))
414
528
  .then((results) => {
415
529
  process.exit(results.suspicious ? 1 : 0);
416
530
  })
@@ -422,13 +536,14 @@ if (command === 'version' || command === '--version' || command === '-v') {
422
536
  const sandboxOpts = options.filter(o => !o.startsWith('-'));
423
537
  const packageName = sandboxOpts[0];
424
538
  const strict = options.includes('--strict');
539
+ const canary = !options.includes('--no-canary');
425
540
  if (!packageName) {
426
- console.log('Usage: muaddib sandbox-report <package-name> [--strict]');
541
+ console.log('Usage: muaddib sandbox-report <package-name> [--strict] [--no-canary]');
427
542
  process.exit(1);
428
543
  }
429
544
 
430
545
  buildSandboxImage()
431
- .then(() => runSandbox(packageName, { strict }))
546
+ .then(() => runSandbox(packageName, { strict, canary }))
432
547
  .then((results) => {
433
548
  if (results.raw_report) {
434
549
  console.log(generateNetworkReport(results.raw_report));
@@ -46,6 +46,7 @@ sleep 1
46
46
 
47
47
  # ── 3. npm install with strace ──
48
48
  echo "[SANDBOX] Installing $PACKAGE..." >&2
49
+ cd /sandbox/install
49
50
  strace -f -e trace=network,process,open,openat,connect,execve,sendto,recvfrom \
50
51
  -o /tmp/strace.log \
51
52
  npm install "$PACKAGE" --ignore-scripts=false > /tmp/install.log 2>&1
@@ -65,8 +66,8 @@ DURATION_MS=$((END_MS - START_MS))
65
66
 
66
67
  # ── 5. Filesystem diff ──
67
68
  echo "[SANDBOX] Analyzing filesystem changes..." >&2
68
- comm -13 /tmp/fs-before.txt /tmp/fs-after.txt | grep -v '^/sandbox/node_modules/' | grep -v '^/tmp/' > /tmp/fs-created.txt
69
- comm -23 /tmp/fs-before.txt /tmp/fs-after.txt | grep -v '^/sandbox/node_modules/' > /tmp/fs-deleted.txt
69
+ comm -13 /tmp/fs-before.txt /tmp/fs-after.txt | grep -v '^/sandbox/install/' | grep -v '^/tmp/' > /tmp/fs-created.txt
70
+ comm -23 /tmp/fs-before.txt /tmp/fs-after.txt | grep -v '^/sandbox/install/' > /tmp/fs-deleted.txt
70
71
 
71
72
  # ── 6. Parse strace ──
72
73
  echo "[SANDBOX] Parsing strace..." >&2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muaddib-scanner",
3
- "version": "1.8.1",
3
+ "version": "2.0.0",
4
4
  "description": "Supply-chain threat detection & response for npm & PyPI/Python",
5
5
  "main": "src/index.js",
6
6
  "bin": {