muaddib-scanner 2.11.139 → 2.11.140

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.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 **20 parallel scanners** (274 detection rules), a **deobfuscation engine**, **inter-module dataflow analysis**, **compound scoring** (17 compound rules), and a gVisor/Docker sandbox to detect known threats and suspicious behavioral patterns in npm and PyPI packages. An XGBoost classifier exists in the codebase but is **currently inactive** (see [Evaluation Metrics](#evaluation-metrics) → ML Classifier section).
33
+ MUAD'DIB combines **21 parallel scanners** (274 detection rules), a **deobfuscation engine**, **inter-module dataflow analysis**, **compound scoring** (20 compound rules), and a gVisor/Docker sandbox to detect known threats and suspicious behavioral patterns in npm and PyPI packages. An XGBoost classifier exists in the codebase but is **currently inactive** (see [Evaluation](#evaluation)).
34
34
 
35
35
  ---
36
36
 
@@ -45,6 +45,16 @@ MUAD'DIB is an educational tool and a free first line of defense. It detects **k
45
45
 
46
46
  ---
47
47
 
48
+ ## Scope
49
+
50
+ **Detects** (npm & PyPI): known-malicious packages (name + SHA256 IOC match), typosquats, install-time RCE (lifecycle `preinstall`/`postinstall`, `curl | sh`, Python import-time, `binding.gyp`), credential read then network exfiltration (intra- and cross-file), obfuscated / high-entropy / stub-loader payloads, binary droppers (`chmod +x` + exec/spawn), and anti-analysis evasion markers.
51
+
52
+ **Out of scope**: browser-only attacks (DOM/`window`, no Node.js API), the *contents* of native binaries / WASM (no binary analysis), zero-day unknown packages (the IOC feed is reactive), and non-npm/PyPI ecosystems (RubyGems, Maven, Go). Determined anti-sandbox fingerprinting and multi-stage remote payloads are known false-negative risks. Full detail: [Threat Model](docs/threat-model.md).
53
+
54
+ **No telemetry.** Your code and scan results never leave your machine — MUAD'DIB only *downloads* threat-intel feeds (`muaddib update`) and, for scoring, reads public npm registry metadata. Webhook alerts are opt-in.
55
+
56
+ ---
57
+
48
58
  ## Installation
49
59
 
50
60
  ### npm (recommended)
@@ -176,7 +186,7 @@ muaddib replay # Ground truth validation (90/94 TPR@3, v2.11
176
186
 
177
187
  ## Features
178
188
 
179
- ### 20 parallel scanners
189
+ ### 21 parallel scanners
180
190
 
181
191
  | Scanner | Detection |
182
192
  |---------|-----------|
@@ -201,10 +211,11 @@ muaddib replay # Ground truth validation (90/94 TPR@3, v2.11
201
211
  | Trusted-Dep-Diff (opt-in) | Diff against trusted dep tarballs from registry (v2.10.x) |
202
212
  | Python Source (PYSRC) | Import-time / install-time RCE patterns in `__init__.py` / `setup.py` (v2.11.41 — closes TrapDoor PyPI gap) |
203
213
  | Python AST (PYAST) | Tree-sitter-Python AST with taint-aware detectors (v2.11.42+) |
214
+ | Anti-Scanner Injection (ASI) | Prompt-injection text in comments/strings that coerces an LLM code reviewer into a clean verdict or into skipping an obfuscated payload (ASI-001..004, Hades campaign 2026-06) |
204
215
 
205
216
  ### 274 detection rules
206
217
 
207
- All rules (269 RULES + 5 PARANOID) are mapped to MITRE ATT&CK techniques. See [SECURITY.md](SECURITY.md#detection-rules-v211117) for the complete rules reference.
218
+ All rules (269 RULES + 5 PARANOID) are mapped to MITRE ATT&CK techniques. See [SECURITY.md](SECURITY.md#detection-rules-v211139) for the complete rules reference.
208
219
 
209
220
  ### Detected campaigns
210
221
 
@@ -278,75 +289,30 @@ With pre-commit framework:
278
289
  ```yaml
279
290
  repos:
280
291
  - repo: https://github.com/DNSZLSK/muad-dib
281
- rev: v2.11.117
292
+ rev: v2.11.139
282
293
  hooks:
283
294
  - id: muaddib-scan
284
295
  ```
285
296
 
286
297
  ---
287
298
 
288
- ## Evaluation Metrics
289
-
290
- Latest measurement: **v2.11.48** (2026-05-26, Track D + PyPI download fix). Ground truth holds 96 samples (94 in-scope, 2 out-of-scope protestware). This run measures the full 94 in-scope set after the 2026-05-25 enrichment (Track C synthetic for the new PYSRC/PYAST/AST-092/AICONF-004/PKG-022 rules, Track A real-world tarballs recovered from VPS archive, Track B reconstructions from the in-house security-review benchmark).
291
-
292
- ### Operational metrics (what an operator actually gets)
293
-
294
- These are the numbers a user gets when running `muaddib scan` against npm or PyPI packages. The pipeline executes scanners + FP caps only — no ML filter is applied (see ML Classifier note below).
295
-
296
- | Metric | Result | Details |
297
- |--------|--------|---------|
298
- | **Wild TPR** (Datadog 17K) | **92.8%** (13,538/14,587 in-scope) | 17,922 packages. 3,335 skipped (no JS). By category: compromised_lib 97.8%, malicious_intent 92.1% — last measurement v2.9.4, independent of GT. |
299
- | **TPR@3** (detection rate, v2.11.48) | **95.74%** (90/94 in-scope) | Full GT re-measurement. Threshold=3: any signal. 13 PyPI samples (was 0). 4 misses incl. 3 browser-only (lottie-player, polyfill-io, trojanized-jquery). |
300
- | **TPR@20** (alert rate, v2.11.48) | **88.30%** (83/94 in-scope) | Operational alert threshold=20. **+3.1pp vs v2.11.47** — Track D `recon_exfil_direct_ip` compound (MUADDIB-COMPOUND-016) closed the GT-095 gap (risk 3→50) and boosted GT-091 byvendors / GT-092 heloo131313 through `linux_fingerprint_exec`. |
301
- | **FPR rules** (Benign curated, v2.11.48 measure) | **1.10%** (6/545 scanned, 548 total) | **Unchanged after Track D** — the new compound + types created zero new FPs (sameFile gate + public-IP-only filter). Drop from 15.6% (v2.10.95) is attributable to FP caps F1-F14 (v2.10.97 → v2.11.31). 6 remaining FPs are real (meteor, prisma, @prisma/client, drizzle-orm, scrypt, liquid). |
302
- | **FPR** (Benign random, v2.11.48) | **2.50%** (5/200) | 200 random npm packages, unchanged. |
303
- | **FPR PyPI** (v2.11.48, first honest measurement) | **9.68%** (12/124 scanned, 132 total) | **Track D fixed the PyPI downloader** — removed `pip --no-binary :all:` flag (forced compile of wheel-only packages, timed out 38% of the time) + added `.whl` extraction via `extractArchive()`. Brought 42 previously-skipped giants (numpy/pandas/django/matplotlib/scikit-learn/...) into scope. All 12 FPs cluster at score 25-35: this is the cap-PyPI-35 artifact, not new rule misfires. Lifting the cap (Track E) would drop FPR PyPI to ≈0%. 8 residual fails are >500MB packages (torch, tensorflow, scipy, opencv-python, ansible…) hitting the 30s `PACK_TIMEOUT_MS`. |
304
- | **ADR** (Adversarial + Holdout, v2.11.48) | **96.26%** (103/107) | 67 adversarial + 40 holdout, global threshold=20. Stable vs v2.10.95. |
305
-
306
- **4414 tests** across 141 files. **266 rules** (261 RULES + 5 PARANOID; v2.11.67/70 Phantom Gyp added PKG-023 + COMPOUND-017).
307
-
308
- **Known issues (v2.11.48):**
309
- - *Cap PyPI à 35/100*: Python samples plafonnent à `riskScore=35` even when `globalRiskScore=100`. Confirmed empirically — all 12 PyPI FPs at score 25-35 (flask 32, django 35, tornado 35, bottle 30, pandas 25, matplotlib 25, plotly 25, bokeh 25, pymongo 35, coverage 32, fabric 35, websockets 35). Lifting the cap will simultaneously drop FPR PyPI to ≈0% and unblock PyPI MALWARE detection at higher thresholds. Track E target.
310
-
311
- ### Operational coverage (v2.11.67-76)
312
-
313
- The static ground-truth TPR above is measured offline. Since v2.11.67 the monitor also tracks **operational** coverage on live npm/PyPI ingestion:
314
- - A per-scan **ledger** (`data/scan-ledger.jsonl`) records every scanned package's outcome; `computeLedgerRollup()` produces a 24h rollup (`alertRate`, per-ecosystem). Note: `alertRate` is a throughput signal, **not** detection TPR.
315
- - An active **GHSA poller** (~15 min; npm, pypi, crates) builds an authoritative "what should we have caught" denominator (`data/ghsa-malware.jsonl`), plus a **feed-health** alarm that fires when an IOC feed silently goes dark.
316
- - The Phase 5 **coverage-audit** (`scripts/coverage-audit.js`, daily 05:00 UTC) joins that denominator against ledger outcomes + the tarball archive to compute an honest GHSA-denominated **operational TPR** (`alerted / total`), and surfaces `scannedClean` misses as human-gated ground-truth candidates.
317
-
318
- This operational TPR is the real production detection rate, distinct from the static GT TPR (which has not been re-measured since v2.11.48).
319
-
320
- ### ML Classifier (offline only)
321
-
322
- `src/ml/classifier.js` is **not wired into `muaddib scan`**. The XGBoost model is currently exercised only by `muaddib evaluate` (offline metric replay) and `muaddib monitor` (LOG-ONLY since 2026-04-08, model collapsed pending retrain — see `src/monitor/queue.js:628`). The v2.11.48 evaluate-time replay shows the same 1.10% FPR (no additional FPs filtered) — kept as a reference for retrain validation, but the published operational FPR is the rules-only number above.
323
-
324
- > **Static evaluation caveats:**
325
- > - TPR measured on the full 94 in-scope samples from the 96-sample ground truth (2 out-of-scope protestware GT-005/GT-009 with `min_threats=0`)
326
- > - TPR@3 = detection rate (any signal); TPR@20 = operational alert threshold
327
- > - FPR rules measured on 548 curated popular npm packages (not a random sample)
328
- > - FPR PyPI: 124/132 scanned (8 download fails on >500MB giants — torch/tensorflow/ansible/…). Smaller N than npm.
329
- > - ADR measured with global threshold (score >= 20) as of v2.6.5
330
-
331
- See [Evaluation Methodology](docs/EVALUATION_METHODOLOGY.md) for the full experimental protocol, holdout history, and Datadog benchmark details.
299
+ ## Evaluation
332
300
 
333
- ### ML ClassifierR&D, currently inactive
301
+ Last measured **v2.11.48** (2026-05-26), **rules-only** (the ML classifier is inactive see below). Ground truth: 94 in-scope real-world attacks + 200 random npm + 124 PyPI + 107 adversarial/holdout.
334
302
 
335
- > **Status (2026-04-08 present):** The XGBoost classifier (`src/ml/classifier.js`) is **not wired into `muaddib scan`** at all, and in `muaddib monitor` it runs in **LOG-ONLY mode** since 2026-04-08 — the trained model collapsed (predicts p≈0.002 for every input, including clearly malicious lifecycle+exec+staged_payload patterns) and was disabled pending retrain on balanced JSONL data. The metrics below come from offline `muaddib evaluate` replay against a frozen bench. They describe what the model *would* contribute if it worked, **not** what an operator gets today.
303
+ | Metric | Result |
304
+ |--------|--------|
305
+ | Detection rate (TPR@3) | **95.74%** (90/94) |
306
+ | Alert rate (TPR@20) | **88.30%** (83/94) |
307
+ | FPR — curated npm (548) | **1.10%** (6/545) |
308
+ | FPR — random npm (200) | **2.50%** (5/200) |
309
+ | FPR — PyPI (132) | **9.68%** (12/124) |
310
+ | ADR — adversarial + holdout | **96.26%** (103/107) |
311
+ | Wild TPR (Datadog 17K) | **92.8%** (13,538/14,587) |
336
312
 
337
- | Metric (offline `evaluate` replay) | Result | Details |
338
- |--------|--------|---------|
339
- | **ML FPR** | **2.85%** (239/8,393 holdout) | XGBoost retrained on 56,564 samples, 64 features, threshold=0.710 |
340
- | **ML TPR** | **99.93%** (2,918/2,920 holdout) | 377 confirmed_malicious via OSSF/GHSA/npm correlation |
341
- | **FPR after ML T1** (offline replay, v2.11.48) | **1.10%** (6/545 scanned) | Classifier filters 0/6 raw FPs in this run (filtered 1 at v2.11.47). Not applied during real scans — `muaddib scan` never invokes the classifier. |
313
+ **ML classifier: inactive.** An XGBoost model lives in `src/ml/` but is never wired into `muaddib scan`, and runs LOG-ONLY in the monitor since 2026-04-08 (the trained model collapsed, pending retrain). All numbers above are rules-only.
342
314
 
343
- > **Retrain methodology (v2.10.51):**
344
- > - Ground truth: 377 confirmed_malicious via auto-labeler (OSSF malicious-packages, GitHub Advisory Database, npm registry takedown correlation)
345
- > - Dataset: 56,564 samples (14,602 malicious, 41,962 clean). Stratified 80/20 split
346
- > - Grid search: depth=4, estimators=300, lr=0.05. AUC-ROC=0.999, F1=0.960
347
- > - Leaky feature filter: 23 dead/leaky features removed (source-identity proxies)
348
- >
349
- > The shadow model continues to log predictions in `muaddib monitor` for retraining validation. When the next model passes shadow validation, the LOG-ONLY guard in `src/monitor/queue.js:660` will be flipped and the metrics above will move back into the operational table.
315
+ Full protocol, per-track history, the PyPI cap-35 caveat, operational (GHSA-denominated) coverage, and the ML retrain methodology: [Evaluation Methodology](docs/EVALUATION_METHODOLOGY.md).
350
316
 
351
317
  ---
352
318
 
@@ -380,7 +346,7 @@ npm test
380
346
 
381
347
  ### Testing
382
348
 
383
- - **4414 tests** across 141 modular test files
349
+ - **4500 tests** across 147 modular test files
384
350
  - **56 fuzz tests** - Malformed inputs, ReDoS, unicode, binary
385
351
  - **Datadog 17K benchmark** - 14,587 confirmed malware samples (in-scope)
386
352
  - **Ground truth validation** - 96 real-world attacks (95.74% TPR@3, 88.30% TPR@20 — v2.11.48 full measure on 94 in-scope)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muaddib-scanner",
3
- "version": "2.11.139",
3
+ "version": "2.11.140",
4
4
  "description": "Supply-chain threat detection & response for npm & PyPI/Python",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -48,16 +48,16 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@inquirer/prompts": "8.5.2",
51
- "acorn": "8.16.0",
51
+ "acorn": "8.17.0",
52
52
  "acorn-walk": "8.3.5",
53
53
  "adm-zip": "0.5.17",
54
- "js-yaml": "4.2.0",
54
+ "js-yaml": "5.1.0",
55
55
  "web-tree-sitter": "^0.26.9"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@eslint/js": "10.0.1",
59
- "eslint": "10.4.1",
59
+ "eslint": "10.5.0",
60
60
  "eslint-plugin-security": "^4.0.0",
61
- "globals": "17.6.0"
61
+ "globals": "17.7.0"
62
62
  }
63
63
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "target": "node_modules",
3
- "timestamp": "2026-07-01T17:07:59.673Z",
3
+ "timestamp": "2026-07-01T20:47:08.448Z",
4
4
  "threats": [
5
5
  {
6
6
  "type": "string_mutation_obfuscation",
@@ -1068,28 +1068,6 @@
1068
1068
  "playbook": "SharedArrayBuffer + Worker Thread detectes. Canal IPC memoire partagee qui contourne la surveillance. Verifier si les workers manipulent des donnees sensibles. Isoler si combine avec eval/exec.",
1069
1069
  "points": 3
1070
1070
  },
1071
- {
1072
- "type": "dangerous_exec",
1073
- "severity": "MEDIUM",
1074
- "message": "[quick-scan] exec/spawn call detected in overflow file.",
1075
- "file": "eslint/lib/rules/eol-last.js",
1076
- "degraded": true,
1077
- "quickScan": true,
1078
- "count": 1,
1079
- "reductions": [],
1080
- "originalSeverity": "MEDIUM",
1081
- "confidenceTier": "low",
1082
- "rule_id": "MUADDIB-AST-007",
1083
- "rule_name": "Dangerous Shell Command Execution",
1084
- "confidence": "high",
1085
- "domain": "malware",
1086
- "references": [
1087
- "https://owasp.org/www-community/attacks/Command_Injection"
1088
- ],
1089
- "mitre": "T1059.004",
1090
- "playbook": "CRITIQUE: Execution de commande shell dangereuse detectee. Isoler la machine. Verifier si la commande a ete executee.",
1091
- "points": 3
1092
- },
1093
1071
  {
1094
1072
  "type": "dangerous_exec",
1095
1073
  "severity": "MEDIUM",
@@ -1468,7 +1446,29 @@
1468
1446
  "type": "dangerous_exec",
1469
1447
  "severity": "MEDIUM",
1470
1448
  "message": "[quick-scan] exec/spawn call detected in overflow file.",
1471
- "file": "js-yaml/lib/type/timestamp.js",
1449
+ "file": "js-yaml/dist/browser/js-yaml.esm.min.mjs",
1450
+ "degraded": true,
1451
+ "quickScan": true,
1452
+ "count": 1,
1453
+ "reductions": [],
1454
+ "originalSeverity": "MEDIUM",
1455
+ "confidenceTier": "low",
1456
+ "rule_id": "MUADDIB-AST-007",
1457
+ "rule_name": "Dangerous Shell Command Execution",
1458
+ "confidence": "high",
1459
+ "domain": "malware",
1460
+ "references": [
1461
+ "https://owasp.org/www-community/attacks/Command_Injection"
1462
+ ],
1463
+ "mitre": "T1059.004",
1464
+ "playbook": "CRITIQUE: Execution de commande shell dangereuse detectee. Isoler la machine. Verifier si la commande a ete executee.",
1465
+ "points": 3
1466
+ },
1467
+ {
1468
+ "type": "dangerous_exec",
1469
+ "severity": "MEDIUM",
1470
+ "message": "[quick-scan] exec/spawn call detected in overflow file.",
1471
+ "file": "js-yaml/dist/browser/js-yaml.umd.min.js",
1472
1472
  "degraded": true,
1473
1473
  "quickScan": true,
1474
1474
  "count": 1,