@lateos/npm-scan 0.15.4 → 0.15.6
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.de.md +7 -2
- package/README.fr.md +7 -2
- package/README.ja.md +7 -2
- package/README.md +55 -29
- package/README.zh.md +7 -2
- package/backend/detectors/cve-2026-48710-badhost/codePattern.js +99 -0
- package/backend/detectors/cve-2026-48710-badhost/findings.js +105 -0
- package/backend/detectors/cve-2026-48710-badhost/index.js +15 -0
- package/backend/detectors/cve-2026-48710-badhost/manifest.js +305 -0
- package/backend/detectors/cve-2026-48710-badhost/transitive.js +189 -0
- package/backend/detectors/index.js +2 -0
- package/backend/detectors/mini-shai-hulud/d5-ioc-check.js +1 -1
- package/backend/detectors/mini-shai-hulud/index.js +41 -3
- package/backend/detectors/mini-shai-hulud/iocs.json +32 -0
- package/backend/vsix-scan/detectors/activation-event-risk.js +116 -0
- package/backend/vsix-scan/detectors/burst-publish.js +52 -0
- package/backend/vsix-scan/detectors/exfil-pattern.js +88 -0
- package/backend/vsix-scan/detectors/known-ioc.js +105 -0
- package/backend/vsix-scan/detectors/orphan-commit-fetch.js +69 -0
- package/backend/vsix-scan/detectors/publisher-anomaly.js +70 -0
- package/backend/vsix-scan/index.js +183 -0
- package/backend/vsix-scan/marketplace-client.js +145 -0
- package/backend/vsix-scan/vsix-iocs.json +31 -0
- package/cli/cli.js +21 -4
- package/package.json +1 -1
package/README.de.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/@lateos/npm-scan)
|
|
10
10
|
[](LICENSING.md)
|
|
11
11
|
[](package.json)
|
|
12
|
-
[](https://github.com/lateos-ai/npm-scan)
|
|
13
13
|
[](https://github.com/lateos-ai/npm-scan)
|
|
14
14
|
[](https://hub.docker.com/r/lateos/npm-scan)
|
|
15
15
|
[](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
|
|
@@ -227,6 +227,7 @@ npm-scan report --pdf # alle Scans (Premium)
|
|
|
227
227
|
| **ATK-009** | Bedingte/schlafende Auslöser (CI-Erkennung, zeitbasiert) | Verhaltensbasiert | 🔴 hoch | SR-9.2 |
|
|
228
228
|
| **ATK-010** | Sandbox-Evasion / Anti-Analyse | Verhaltensbasiert | 🟠 mittel | SR-10.3 |
|
|
229
229
|
| **ATK-011** | Transitive Verbreitung (wurmartige laterale Ausbreitung) | Verhaltensbasiert | 🔴 hoch | SR-11.4 |
|
|
230
|
+
| **CVE-2026-48710** | BadHost — Starlette Authentifizierungs-Bypass via Host-Header-Injection (CVE-2026-48710, CVSS 7.0). Python-Abhängigkeitsversionserkennung (requirements.txt, pyproject.toml, poetry.lock, Pipfile, setup.py/cfg), transitive Heuristik (15 bekannte Downstream-Pakete: fastapi, vllm, litellm, MCP-Server, etc.), statische Code-Pattern-Analyse für gefährliche `request.url.path`-Nutzung in Auth/Middleware-Kontexten mit `request.scope["path"]`-Unterdrückung | Statisch + Registry | 🔴 hoch / 🟠 mittel / ℹ️ info | SR-3.1, SR-5.3 |
|
|
230
231
|
|
|
231
232
|
> **Wie ausweichende Angriffe erkannt werden:** ATK-009 erkennt Pakete, die `process.env.CI` prüfen, Hostnamen sondieren oder zeitbasierte Aktivierung verwenden. ATK-010 markiert `debugger`-Anweisungen, `os.hostname()`-Sonden und Umgebungs-Fingerprinting. ATK-011 verfolgt Peer-Abhängigkeitsgraphen, um wurmartige Verbreitungsmuster zu erkennen.
|
|
232
233
|
> Vollständige Dokumentation der Ausweichfläche und PoC-Beispiele finden Sie in [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md).
|
|
@@ -548,7 +549,7 @@ Siehe den obigen [Docker-Schnellstart-Abschnitt](#-lateosnpm-scan-überall-mit-d
|
|
|
548
549
|
|
|
549
550
|
### Kostenlose Stufe (ausgeliefert)
|
|
550
551
|
|
|
551
|
-
- Alle 11 ATK-Detektoren (statisch + verhaltensbasiert)
|
|
552
|
+
- Alle 11 ATK-Detektoren (statisch + verhaltensbasiert) + **MEGALODON** + **HF_IMPERSONATION** + **MINI_SHAI_HULUD** + **VSIX_SCAN** + **CVE-2026-48710 (BadHost)**
|
|
552
553
|
- SBOM-Ausgabe (CycloneDX + SPDX)
|
|
553
554
|
- HTML-, Text- und Compliance-Berichte (NIST + EU CRA)
|
|
554
555
|
- Policy-as-Code-Engine (YAML)
|
|
@@ -611,6 +612,10 @@ node --test test/detectors-corpus.test.js
|
|
|
611
612
|
- `test/fetch.test.js` — Tarball-Extraktion, Bereinigung temporärer Verzeichnisse
|
|
612
613
|
- `test/policy-edge-cases.test.js` — Grenzfälle bei Unterdrückung, Überschreibung, Ladevalidierung
|
|
613
614
|
- `test/report-snapshots.test.js` — HTML/Text/CRA/PDF-Format-Assertions
|
|
615
|
+
- `test/cve-2026-48710-badhost/manifest.test.js` — 13 Python-Manifest-Parsing-Tests (requirements.txt, pyproject.toml, poetry.lock, Version-Grenzfälle)
|
|
616
|
+
- `test/cve-2026-48710-badhost/transitive.test.js` — 7 transitive Abhängigkeitstests (Tier 1/2, fastapi-Version-Gating, Pin-Unterdrückung)
|
|
617
|
+
- `test/cve-2026-48710-badhost/codePattern.test.js` — 6 statische Code-Pattern-Tests (Auth-Kontext, INFO-Durchgriff, Scope-Unterdrückung)
|
|
618
|
+
- `test/cve-2026-48710-badhost/integration.test.js` — 4 Integrationstests (End-to-End-Composite-Findings, sauberes Projekt, keine Python-Dateien)
|
|
614
619
|
- `test/cli.test.js` — Commander-Integrationstests (Hilfe, Version, Scan, Bericht, Fehlerbehandlung)
|
|
615
620
|
|
|
616
621
|
### Hilfe benötigt?
|
package/README.fr.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/@lateos/npm-scan)
|
|
10
10
|
[](LICENSING.md)
|
|
11
11
|
[](package.json)
|
|
12
|
-
[](https://github.com/lateos-ai/npm-scan)
|
|
13
13
|
[](https://github.com/lateos-ai/npm-scan)
|
|
14
14
|
[](https://hub.docker.com/r/lateos/npm-scan)
|
|
15
15
|
[](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
|
|
@@ -227,6 +227,7 @@ npm-scan report --pdf # tous les scans (premium)
|
|
|
227
227
|
| **ATK-009** | Déclencheurs conditionnels/dormants (détection CI, temporel) | Comportementale | 🔴 élevée | SR-9.2 |
|
|
228
228
|
| **ATK-010** | Contournement de sandbox / anti-analyse | Comportementale | 🟠 moyenne | SR-10.3 |
|
|
229
229
|
| **ATK-011** | Propagation transitive (dissémination latérale de type ver) | Comportementale | 🔴 élevée | SR-11.4 |
|
|
230
|
+
| **CVE-2026-48710** | BadHost — contournement d'authentification Starlette par injection d'en-tête Host (CVE-2026-48710, CVSS 7.0). Détection de version de dépendance Python (requirements.txt, pyproject.toml, poetry.lock, Pipfile, setup.py/cfg), heuristique transitive (15 paquets aval connus : fastapi, vllm, litellm, serveurs MCP, etc.), analyse statique de code pour `request.url.path` dangereux en contexte auth/middleware avec suppression par `request.scope["path"]` | Statique + Registre | 🔴 élevée / 🟠 moyenne / ℹ️ info | SR-3.1, SR-5.3 |
|
|
230
231
|
|
|
231
232
|
> **Comment les attaques furtives sont détectées :** ATK-009 détecte les paquets qui vérifient `process.env.CI`, sondent les noms d'hôte ou utilisent une activation temporelle. ATK-009 signale les instructions `debugger`, les sondes `os.hostname()` et l'empreinte environnementale. ATK-011 trace les graphes de dépendances peer pour détecter les schémas de propagation de type ver.
|
|
232
233
|
> Voir [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md) pour la documentation complète de la surface d'évasion et des exemples de PoC.
|
|
@@ -548,7 +549,7 @@ Voir la [section Démarrage rapide Docker](#-exécutez-lateosnpm-scan-partout-av
|
|
|
548
549
|
|
|
549
550
|
### Niveau gratuit (livré)
|
|
550
551
|
|
|
551
|
-
- Les 11 détecteurs ATK (statique + comportemental)
|
|
552
|
+
- Les 11 détecteurs ATK (statique + comportemental) + **MEGALODON** + **HF_IMPERSONATION** + **MINI_SHAI_HULUD** + **VSIX_SCAN** + **CVE-2026-48710 (BadHost)**
|
|
552
553
|
- Sortie SBOM (CycloneDX + SPDX)
|
|
553
554
|
- Rapports HTML, texte et conformité (NIST + EU CRA)
|
|
554
555
|
- Moteur de politique en tant que code (YAML)
|
|
@@ -611,6 +612,10 @@ node --test test/detectors-corpus.test.js
|
|
|
611
612
|
- `test/fetch.test.js` — extraction de tarball, nettoyage de répertoire temporaire
|
|
612
613
|
- `test/policy-edge-cases.test.js` — cas limites dans la suppression, la surcharge, la validation de chargement
|
|
613
614
|
- `test/report-snapshots.test.js` — assertions de format HTML/texte/CRA/PDF
|
|
615
|
+
- `test/cve-2026-48710-badhost/manifest.test.js` — 13 tests d'analyse de manifeste Python (requirements.txt, pyproject.toml, poetry.lock, cas limites de version)
|
|
616
|
+
- `test/cve-2026-48710-badhost/transitive.test.js` — 7 tests de dépendances transitives (Tier 1/2, contrôle de version fastapi, suppression par épinglage)
|
|
617
|
+
- `test/cve-2026-48710-badhost/codePattern.test.js` — 6 tests de motifs de code statiques (contexte auth, passage INFO, suppression scope)
|
|
618
|
+
- `test/cve-2026-48710-badhost/integration.test.js` — 4 tests d'intégration (résultats composites de bout en bout, projet propre, pas de fichiers Python)
|
|
614
619
|
- `test/cli.test.js` — tests d'intégration commander (aide, version, scan, rapport, gestion d'erreurs)
|
|
615
620
|
|
|
616
621
|
### Besoin d'aide ?
|
package/README.ja.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/@lateos/npm-scan)
|
|
10
10
|
[](LICENSING.md)
|
|
11
11
|
[](package.json)
|
|
12
|
-
[](https://github.com/lateos-ai/npm-scan)
|
|
13
13
|
[](https://github.com/lateos-ai/npm-scan)
|
|
14
14
|
[](https://hub.docker.com/r/lateos/npm-scan)
|
|
15
15
|
[](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
|
|
@@ -223,6 +223,7 @@ npm-scan report --pdf # すべてのスキャン(プレミアム
|
|
|
223
223
|
| **ATK-009** | 条件付き/潜伏トリガー(CI検出、時間ベース) | 行動 | 🔴 高 | SR-9.2 |
|
|
224
224
|
| **ATK-010** | サンドボックス回避/アンチ解析 | 行動 | 🟠 中 | SR-10.3 |
|
|
225
225
|
| **ATK-011** | 推移的伝播(ワーム型横方向拡散) | 行動 | 🔴 高 | SR-11.4 |
|
|
226
|
+
| **CVE-2026-48710** | BadHost — Starlette Host ヘッダーインジェクション認証バイパス (CVE-2026-48710, CVSS 7.0)。Python 依存関係バージョン検出 (requirements.txt, pyproject.toml, poetry.lock, Pipfile, setup.py/cfg)、推移的ヒューリスティック (15 の既知ダウンストリームパッケージ:fastapi, vllm, litellm, MCP サーバー等)、auth/middleware コンテキストでの危険な `request.url.path` 使用の静的コードパターンスキャン、`request.scope["path"]` による抑制対応 | 静的 + レジストリ | 🔴 高 / 🟠 中 / ℹ️ 情報 | SR-3.1, SR-5.3 |
|
|
226
227
|
|
|
227
228
|
> **回避型攻撃の捕捉方法:** ATK-009は`process.env.CI`をチェックする、ホスト名をプローブする、または時間ベースのアクティベーションを使用するパッケージを検出します。ATK-010は`debugger`文、`os.hostname()`プローブ、環境フィンガープリンティングをフラグ付けします。ATK-011はピア依存関係グラフをトレースしてワーム型伝播パターンを検出します。
|
|
228
229
|
> 完全な回避面のドキュメントとPoC例については、[`docs/attack-taxonomy.md`](docs/attack-taxonomy.md)を参照してください。
|
|
@@ -544,7 +545,7 @@ npm-scan report --html > report.html
|
|
|
544
545
|
|
|
545
546
|
### 無料版(出荷済み)
|
|
546
547
|
|
|
547
|
-
- 全11ATK
|
|
548
|
+
- 全11ATK検出器(静的+行動)+ **MEGALODON** + **HF_IMPERSONATION** + **MINI_SHAI_HULUD** + **VSIX_SCAN** + **CVE-2026-48710 (BadHost)**
|
|
548
549
|
- SBOM出力(CycloneDX + SPDX)
|
|
549
550
|
- HTML、テキスト、コンプライアンスレポート(NIST + EU CRA)
|
|
550
551
|
- ポリシー・アズ・コードエンジン(YAML)
|
|
@@ -607,6 +608,10 @@ node --test test/detectors-corpus.test.js
|
|
|
607
608
|
- `test/fetch.test.js` — tarball抽出、一時ディレクトリクリーンアップ
|
|
608
609
|
- `test/policy-edge-cases.test.js` — 抑制、上書き、ロード検証のエッジケース
|
|
609
610
|
- `test/report-snapshots.test.js` — HTML/テキスト/CRA/PDF形式のアサーション
|
|
611
|
+
- `test/cve-2026-48710-badhost/manifest.test.js` — 13のPythonマニフェスト解析テスト(requirements.txt, pyproject.toml, poetry.lock, バージョンエッジケース)
|
|
612
|
+
- `test/cve-2026-48710-badhost/transitive.test.js` — 7の推移的依存関係テスト(Tier 1/2, fastapiバージョンゲーティング, 固定抑制)
|
|
613
|
+
- `test/cve-2026-48710-badhost/codePattern.test.js` — 6の静的コードパターンテスト(authコンテキスト, INFOフォールスルー, scope抑制)
|
|
614
|
+
- `test/cve-2026-48710-badhost/integration.test.js` — 4の統合テスト(エンドツーエンド複合発見項目, クリーンプロジェクト, Pythonファイルなし)
|
|
610
615
|
- `test/cli.test.js` — commander統合テスト(ヘルプ、バージョン、スキャン、レポート、エラーハンドリング)
|
|
611
616
|
|
|
612
617
|
### ヘルプが必要ですか?
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@lateos/npm-scan)
|
|
4
4
|
[](LICENSING.md)
|
|
5
5
|
[](package.json)
|
|
6
|
-
[](https://github.com/lateos-ai/npm-scan)
|
|
7
7
|
[](https://github.com/lateos-ai/npm-scan)
|
|
8
8
|
[](https://hub.docker.com/r/lateos/npm-scan)
|
|
9
9
|
[](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
|
|
@@ -28,6 +28,8 @@ A growing attack vector is **HuggingFace org impersonation** — packages that m
|
|
|
28
28
|
|
|
29
29
|
The **Megalodon campaign** (2026) alone compromised 5,500+ repositories via fake GitHub PRs, malicious workflow injection, and cloud credential exfiltration — all coordinated through a single actor automating the entire kill chain. **@lateos/npm-scan** now detects artifacts of this campaign out of the box.
|
|
30
30
|
|
|
31
|
+
Critical infrastructure vulnerabilities in the Python ecosystem are also in scope. The **BadHost (CVE-2026-48710)** vulnerability in Starlette < 1.0.1 enables authentication bypass via unvalidated HTTP Host header injection, affecting FastAPI, vLLM, LiteLLM, MCP servers, and any project using Starlette transitively — now detected across Python manifests, transitive dependency chains, and source code patterns in a single scan.
|
|
32
|
+
|
|
31
33
|
**npm audit** checks known CVEs. **Snyk** scans for vulnerabilities. **Socket** looks at package behavior. None of them were designed for the generation of attacks that emerged in 2025 — attacks that look benign until they reach production.
|
|
32
34
|
|
|
33
35
|
**@lateos/npm-scan** was built for this moment.
|
|
@@ -47,7 +49,10 @@ The **Megalodon campaign** (2026) alone compromised 5,500+ repositories via fake
|
|
|
47
49
|
| Sandbox evasion detection (ATK-010) | ❌ | ❌ | ❌ | ✅ |
|
|
48
50
|
| Transitive worm propagation (ATK-011) | ❌ | ❌ | ❌ | ✅ |
|
|
49
51
|
| Campaign detection (Megalodon CI/CD) | ❌ | ❌ | ❌ | ✅ |
|
|
52
|
+
| Worm campaign detection (Mini Shai-Hulud Wave 1–3) | ❌ | ❌ | ❌ | ✅ |
|
|
50
53
|
| HF model repo impersonation + README clone | ❌ | ❌ | ❌ | ✅ |
|
|
54
|
+
| VS Code extension supply chain scan (--vsix) | ❌ | ❌ | ❌ | ✅ |
|
|
55
|
+
| Python vulnerability detection (CVE-2026-48710 BadHost) | ❌ | ❌ | ❌ | ✅ |
|
|
51
56
|
| Attack taxonomy (ATK series) | ❌ | ❌ | ❌ | ✅ |
|
|
52
57
|
| SBOM output (CycloneDX + SPDX) | ❌ | ✅ | ❌ | ✅ |
|
|
53
58
|
| SARIF v2.1 (GitHub Code Scanning) | ❌ | ❌ | ❌ | ✅ |
|
|
@@ -68,6 +73,9 @@ The **Megalodon campaign** (2026) alone compromised 5,500+ repositories via fake
|
|
|
68
73
|
| 🕵️ | **Heuristic static analysis** | AST-level inspection catches obfuscation, eval chains, env probing, and suspicious lifecycle scripts that regex-based tools miss |
|
|
69
74
|
| 🧠 | **Behavioral detection** | Identifies conditional triggers (time-based, CI-aware), sandbox evasion, and dormant activation patterns |
|
|
70
75
|
| 🧬 | **ATK attack taxonomy** | 11 classified attack types with NIST 800-161 mappings — versioned, documented, and PR-able |
|
|
76
|
+
| 🪱 | **Worm campaign detection** | Mini Shai-Hulud — 6 sub-checks detecting burst publish, sibling compromise, SLSA attestation mismatch, publisher drift, IOC match, and token exfil across 3 waves (TanStack, AntV/atool, Nx Console) |
|
|
77
|
+
| 🧩 | **VSIX extension scanning** | `npm-scan scan --vsix nrwl.angular-console` — detects VS Code Marketplace supply chain attacks: burst publish, publisher anomaly, activation event risk, orphan commit fetch, known IOC, and exfil patterns (Nx Console 18.95.0 CVE-2026-48027) |
|
|
78
|
+
| 🐍 | **Python vulnerability detection** | CVE-2026-48710 (BadHost) — Starlette Host header injection across 6 Python manifest formats, 15 transitive downstream packages (fastapi, vllm, litellm, MCP), and static `request.url.path` code pattern analysis with `scope["path"]` suppression |
|
|
71
79
|
| 📦 | **SBOM generation** | CycloneDX 1.5 and SPDX 2.3 with findings embedded as vulnerabilities |
|
|
72
80
|
| 🔍 | **SARIF output** | GitHub Advanced Security / CodeQL compatible SARIF v2.1 — shows findings directly in Security tab |
|
|
73
81
|
| 🧾 | **Compliance reporting** | NIST SP 800-161 traceability matrix + EU Cyber Resilience Act mapping (free tier) |
|
|
@@ -193,41 +201,28 @@ npm-scan scan some-package --policy .npm-scan.yml
|
|
|
193
201
|
|
|
194
202
|
# Scan a local tarball (no registry fetch needed)
|
|
195
203
|
npm-scan scan --file path/to/malicious-package.tgz
|
|
204
|
+
|
|
205
|
+
# Scan a VS Code extension for Marketplace supply chain attacks
|
|
206
|
+
npm-scan scan --vsix nrwl.angular-console
|
|
207
|
+
|
|
208
|
+
# Scan a package AND a VSIX extension together (findings merge)
|
|
209
|
+
npm-scan scan lodash --vsix nrwl.angular-console
|
|
196
210
|
```
|
|
197
211
|
|
|
198
212
|
### Scan a lockfile
|
|
199
213
|
|
|
200
214
|
```bash
|
|
201
|
-
# Scan
|
|
202
|
-
npm-scan scan
|
|
203
|
-
|
|
204
|
-
# Scan a specific lockfile
|
|
205
|
-
npm-scan scan-lockfile -f ./path/to/package-lock.json
|
|
206
|
-
|
|
207
|
-
# Scan yarn.lock or pnpm-lock.yaml
|
|
208
|
-
npm-scan scan-lockfile -f ./yarn.lock --yarn
|
|
209
|
-
npm-scan scan-lockfile -f ./pnpm-lock.yaml --pnpm
|
|
210
|
-
|
|
211
|
-
# Fail CI/CD on high or critical findings (exit code 1)
|
|
212
|
-
npm-scan scan-lockfile --fail-on high
|
|
213
|
-
|
|
214
|
-
# Fail on any findings (low and above)
|
|
215
|
-
npm-scan scan-lockfile --fail-on low
|
|
216
|
-
|
|
217
|
-
# Generate SARIF v2.1 output for GitHub Advanced Security / VS Code
|
|
218
|
-
npm-scan scan-lockfile --sarif results.sarif
|
|
219
|
-
|
|
220
|
-
# Watch for changes and auto-rescan (single lockfile)
|
|
221
|
-
npm-scan scan-lockfile --watch
|
|
215
|
+
# Scan a single package
|
|
216
|
+
npm-scan scan lodash
|
|
222
217
|
|
|
223
|
-
#
|
|
224
|
-
npm-scan scan-lockfile
|
|
218
|
+
# Scan your lockfile
|
|
219
|
+
npm-scan scan-lockfile
|
|
225
220
|
|
|
226
|
-
#
|
|
227
|
-
npm-scan scan
|
|
221
|
+
# Scan a VS Code extension for supply chain threats
|
|
222
|
+
npm-scan scan --vsix nrwl.angular-console
|
|
228
223
|
|
|
229
|
-
#
|
|
230
|
-
npm-scan
|
|
224
|
+
# View latest scans
|
|
225
|
+
npm-scan report
|
|
231
226
|
```
|
|
232
227
|
|
|
233
228
|
### Generate reports
|
|
@@ -288,10 +283,16 @@ npm-scan report --pdf # all scans (premium)
|
|
|
288
283
|
| **ATK-011** | Transitive propagation (worm-style lateral spread) | Behavioral | 🔴 high | SR-11.4 |
|
|
289
284
|
| **MEGALODON** | Megalodon CI/CD campaign — workflow C2 exfil, credential harvest, publish velocity spike, publisher drift | Static + Registry | ⚫ critical | SR-3.1, SR-7.5 |
|
|
290
285
|
| **HF_IMPERSONATION** | HuggingFace org spoof detection — Jaro-Winkler similarity against 15 known-good orgs, SimHash README clone detection, artifact mismatch (`.exe`/`.dll` in model repos), postinstall escalation, new-org amplifier | Static + Network (Stage 2) | 🔴 high / ⚫ critical | SR-2.1 |
|
|
286
|
+
| **MINI_SHAI_HULUD** | Mini Shai-Hulud worm campaign — burst publish velocity (≥3 versions/30 min), co-temporal sibling compromise, SLSA attestation mismatch (sub-60s gap, first-ever, builder mismatch), publisher drift (<10 min account change), IOC match (scope/sha512/publisher from seed file), token exfil (NPM_TOKEN/.npmrc/atob patterns), Nx Console downstream detection | Static + Registry | 🔴 high / ⚫ critical | SR-3.1, SR-7.5 |
|
|
287
|
+
| **VSIX_SCAN** | VS Code extension supply chain scan — burst publish (≥2 versions/30 min, hot-pull <20 min), publisher anomaly (account substitution, new-account on high-install ext, 15-min add+publish), activation event risk (onStartupFinished→HIGH, *→CRITICAL, escalation on shell keywords), orphan commit fetch (GitHub API SHA refs, npx git URL, MCP-disguised exfil, Bun install), known IOC (extensionId/publisherAccount/commit hash from seed), exfil patterns (cred paths, DNS tunneling, AES+RSA, anti-analysis, Bun APIs) | Static + Registry | 🟠 medium / 🔴 high / ⚫ critical | SR-3.1, SR-5.3 |
|
|
288
|
+
| **CVE-2026-48710** | BadHost — Starlette authentication bypass via Host header injection (CVE-2026-48710, CVSS 7.0). Python dependency version detection (requirements.txt, pyproject.toml, poetry.lock, Pipfile, setup.py/cfg), transitive heuristic (15 known downstream packages: fastapi, vllm, litellm, MCP servers, etc.), static code pattern scan for dangerous `request.url.path` usage in auth/middleware context with `request.scope["path"]` suppression | Static + Registry | 🔴 high / 🟠 medium / ℹ️ info | SR-3.1, SR-5.3 |
|
|
291
289
|
|
|
292
290
|
> **How evasive attacks are caught:** ATK-009 detects packages that check `process.env.CI`, probe hostnames, or use time-based activation. ATK-010 flags `debugger` statements, `os.hostname()` probes, and env fingerprinting. ATK-011 traces peer dependency graphs to detect worm-like propagation patterns.
|
|
293
291
|
> **MEGALODON** campaign detection analyzes bundled `.github/workflows/` files for C2 co-occurrence and base64 decode chains, scans tarball files for credential + outbound network patterns, detects version publish velocity spikes via npm registry metadata, and identifies publisher account drift — all without any network calls beyond the initial package fetch.
|
|
294
292
|
> **HF_IMPERSONATION** detection uses a lazy two-stage evaluation: Stage 1 scans `package.json` scripts and JS/TS sources for HuggingFace references (URLs, `from_pretrained()`, `hub.download()`) and runs Jaro-Winkler similarity against 15 known-good HF orgs — zero network. If spoofs are found, Stage 2 fetches the HF model API, computes SimHash of both READMEs for clone detection, validates artifact type consistency (e.g., `transformers` library with `.exe` files is flagged as critical), applies a new-org amplifier (<30 days), and escalates when the reference appears in a lifecycle script.
|
|
293
|
+
> **MINI_SHAI_HULUD** worm campaign detection uses a lazy two-stage evaluation: Stage 1 runs burst velocity, publisher drift, IOC, and token exfil checks (in-memory, no network). If burst triggers, Stage 2 queries npm attestation endpoints for SLSA anomalies and fetches sibling package registry metadata for co-temporal burst detection. Composite finding includes wave attribution (wave1-tanstack, wave2-antv, wave3-nx-console) and critical severity when SLSA or IOC match. NX_CONSOLE_DOWNSTREAM (D7) flags npm packages with `@nx/*` dependencies and checks for `nrwl.angular-console` in `.vscode/extensions.json`.
|
|
294
|
+
> **VSIX_SCAN** extension scanning wraps both VS Code Marketplace and Open VSX registries with rate-limited (10 req/min), cached (5 min TTL) API clients. All 6 detectors run asynchronously and aggregate into a single composite `VSIX_SCAN` finding. Zero extension code is executed — all analysis is static regex/text-pattern matching. No Bun installation required for Bun pattern detection.
|
|
295
|
+
> **CVE-2026-48710 (BadHost)** detection uses three independent layers: Layer 1 parses 6 Python manifest formats (requirements.txt, pyproject.toml, poetry.lock, Pipfile, setup.py, setup.cfg) with PEP 440 semver-aware version comparison. Layer 2 scans for 15 known Starlette-downstream packages with Tier 1 (HIGH confidence) and Tier 2 (MEDIUM confidence) transitive heuristics, suppressed by explicit `starlette >= 1.0.1` pin. Layer 3 performs function-boundary static analysis on `.py` files for `request.url.path` usage, escalating to MEDIUM severity in auth/middleware contexts and suppressing when `request.scope["path"]` is used in the same function.
|
|
295
296
|
> See [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md) for full evasion surface documentation and PoC examples.
|
|
296
297
|
|
|
297
298
|
---
|
|
@@ -367,6 +368,18 @@ npm-scan scan target --policy .npm-scan.yml
|
|
|
367
368
|
| `NPM_SCAN_LICENSE_KEY` | Premium / enterprise license key | — |
|
|
368
369
|
| `NPM_SCAN_DATA_DIR` | Scan history directory | `./.npm-scan` |
|
|
369
370
|
| `NPM_SCAN_LOG_LEVEL` | Log verbosity | `info` |
|
|
371
|
+
| `NPM_SCAN_LICENSE_SECRET` | HMAC key for license generation/validation | `npm-scan-default-dev-key` |
|
|
372
|
+
|
|
373
|
+
### IOC configuration
|
|
374
|
+
|
|
375
|
+
Campaign detectors use seed IOC files for known-malicious fingerprints:
|
|
376
|
+
|
|
377
|
+
| IOC File | Detector | Types |
|
|
378
|
+
|----------|----------|-------|
|
|
379
|
+
| `backend/detectors/mini-shai-hulud/iocs.json` | Mini Shai-Hulud (Waves 1–3) | `packageScope`, `publisherAccount`, `sha512`, `extensionId` |
|
|
380
|
+
| `backend/vsix-scan/vsix-iocs.json` | VSIX extension scan | `extensionId`, `publisherAccount`, `orphanCommitHash` |
|
|
381
|
+
|
|
382
|
+
IOC files follow a unified schema (`iocs: [{ type, value, ... }]`) and are loaded at module init. Update them from your threat intel feed to extend detection coverage without code changes.
|
|
370
383
|
|
|
371
384
|
### Premium licensing
|
|
372
385
|
|
|
@@ -638,7 +651,7 @@ See the [Docker quick-start section](#-run-lateosnpm-scan-anywhere-with-docker--
|
|
|
638
651
|
|
|
639
652
|
### Free tier (shipped)
|
|
640
653
|
|
|
641
|
-
- All 11 ATK detectors + **MEGALODON** CI/CD campaign detection (D1–D6) + **HF_IMPERSONATION** detector
|
|
654
|
+
- All 11 ATK detectors + **MEGALODON** CI/CD campaign detection (D1–D6) + **HF_IMPERSONATION** detector + **MINI_SHAI_HULUD** worm campaign (D1–D7, 3 waves) + **VSIX_SCAN** extension supply chain scan (6 detectors) + **CVE-2026-48710 (BadHost)** Python vulnerability detection (3 layers)
|
|
642
655
|
- SBOM output (CycloneDX + SPDX)
|
|
643
656
|
- HTML, text, and compliance reports (NIST + EU CRA)
|
|
644
657
|
- Policy-as-code engine (YAML)
|
|
@@ -647,6 +660,7 @@ See the [Docker quick-start section](#-run-lateosnpm-scan-anywhere-with-docker--
|
|
|
647
660
|
- Pre-commit hook (husky + lint-staged)
|
|
648
661
|
- Docker images + Compose pipeline
|
|
649
662
|
- Watch mode (--watch / --monorepo for auto-rescan)
|
|
663
|
+
- VS Code extension scanning (--vsix flag with Marketplace + Open VSX registries)
|
|
650
664
|
|
|
651
665
|
### Premium (🔐 license key)
|
|
652
666
|
|
|
@@ -708,6 +722,18 @@ node --test test/detectors-corpus.test.js
|
|
|
708
722
|
- `test/report.test.js` — SARIF, CSV, STIG, risk score format tests
|
|
709
723
|
- `test/lockfile.test.js` — npm/yarn/pnpm parser, auto-detect, ATK-007/011 lockfile tests
|
|
710
724
|
- `test/hf-impersonation.test.js` — 13 HF impersonation detection tests (no-ref, exact match, spoof, README clone, artifact mismatch, postinstall escalation, new-org tag)
|
|
725
|
+
- `test/mini-shai-hulud.test.js` — 22 Mini Shai-Hulud worm campaign detection tests (burst, sibling, SLSA, maintainer, IOC, exfil, wave attribution)
|
|
726
|
+
- `test/vsix-scan/burst-publish.test.js` — 4 VSIX burst publish tests (threshold, sub-threshold, hot-pull, Open VSX window)
|
|
727
|
+
- `test/vsix-scan/publisher-anomaly.test.js` — 5 publisher anomaly tests (cross-namespace, new-account, add+publish, substitution, silent)
|
|
728
|
+
- `test/vsix-scan/activation-event-risk.test.js` — 5 activation event risk tests (onStartupFinished, wildcard, escalation, first-time, silent)
|
|
729
|
+
- `test/vsix-scan/orphan-commit-fetch.test.js` — 5 orphan commit tests (GitHub SHA, npx git, MCP exfil, Bun install, silent)
|
|
730
|
+
- `test/vsix-scan/known-ioc.test.js` — 4 known IOC tests (extensionId, publisher window, outside window)
|
|
731
|
+
- `test/vsix-scan/exfil-pattern.test.js` — 5 exfil pattern tests (creds, DNS tunnel, AES+RSA, anti-analysis, silent)
|
|
732
|
+
- `test/vsix-scan/integration.test.js` — 4 integration tests (Nx Console CRITICAL, safe version clean, orphan commit, skipNetwork)
|
|
733
|
+
- `test/cve-2026-48710-badhost/manifest.test.js` — 13 Python manifest parsing tests (requirements.txt, pyproject.toml, poetry.lock, version edge cases)
|
|
734
|
+
- `test/cve-2026-48710-badhost/transitive.test.js` — 7 transitive dependency tests (Tier 1/2, fastapi version gating, pin suppression)
|
|
735
|
+
- `test/cve-2026-48710-badhost/codePattern.test.js` — 6 static code pattern tests (auth context, INFO fallthrough, scope suppression)
|
|
736
|
+
- `test/cve-2026-48710-badhost/integration.test.js` — 4 integration tests (end-to-end composite findings, clean project, no Python files)
|
|
711
737
|
- `test/cli.test.js` — commander integration tests (help, version, scan, report, error handling)
|
|
712
738
|
- `test/cli-lockfile.test.js` — scan-lockfile CLI options, yarn/pnpm/monorepo/watch tests
|
|
713
739
|
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/@lateos/npm-scan)
|
|
10
10
|
[](LICENSING.md)
|
|
11
11
|
[](package.json)
|
|
12
|
-
[](https://github.com/lateos-ai/npm-scan)
|
|
13
13
|
[](https://github.com/lateos-ai/npm-scan)
|
|
14
14
|
[](https://hub.docker.com/r/lateos/npm-scan)
|
|
15
15
|
[](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
|
|
@@ -227,6 +227,7 @@ npm-scan report --pdf # 所有扫描(高级版)
|
|
|
227
227
|
| **ATK-009** | 条件/潜伏触发器(CI 检测、基于时间) | 行为 | 🔴 高 | SR-9.2 |
|
|
228
228
|
| **ATK-010** | 沙箱逃逸 / 反分析 | 行为 | 🟠 中 | SR-10.3 |
|
|
229
229
|
| **ATK-011** | 传递性传播(蠕虫式横向扩散) | 行为 | 🔴 高 | SR-11.4 |
|
|
230
|
+
| **CVE-2026-48710** | BadHost — Starlette Host 头注入认证绕过 (CVE-2026-48710, CVSS 7.0)。Python 依赖版本检测 (requirements.txt, pyproject.toml, poetry.lock, Pipfile, setup.py/cfg),传递性启发式检测 (15 个已知下游包:fastapi, vllm, litellm, MCP 服务器等),auth/middleware 上下文中危险 `request.url.path` 使用的静态代码模式扫描,支持 `request.scope["path"]` 抑制 | 静态 + 注册表 | 🔴 高 / 🟠 中 / ℹ️ 信息 | SR-3.1, SR-5.3 |
|
|
230
231
|
|
|
231
232
|
> **如何捕获逃避式攻击:** ATK-009 检测检查 `process.env.CI`、探测主机名或使用时间激活的包。ATK-010 标记 `debugger` 语句、`os.hostname()` 探测和环境指纹采集。ATK-011 追踪同级依赖图以检测蠕虫式传播模式。
|
|
232
233
|
> 完整逃避面文档和 PoC 示例请参阅 [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md)。
|
|
@@ -548,7 +549,7 @@ npm-scan report --html > report.html
|
|
|
548
549
|
|
|
549
550
|
### 免费版(已发布)
|
|
550
551
|
|
|
551
|
-
- 全部 11 个 ATK 检测器(静态 +
|
|
552
|
+
- 全部 11 个 ATK 检测器(静态 + 行为)+ **MEGALODON** + **HF_IMPERSONATION** + **MINI_SHAI_HULUD** + **VSIX_SCAN** + **CVE-2026-48710 (BadHost)**
|
|
552
553
|
- SBOM 输出(CycloneDX + SPDX)
|
|
553
554
|
- HTML、文本和合规报告(NIST + EU CRA)
|
|
554
555
|
- 策略即代码引擎(YAML)
|
|
@@ -611,6 +612,10 @@ node --test test/detectors-corpus.test.js
|
|
|
611
612
|
- `test/fetch.test.js` — tarball 提取、临时目录清理
|
|
612
613
|
- `test/policy-edge-cases.test.js` — 抑制、覆盖、加载验证的边缘情况
|
|
613
614
|
- `test/report-snapshots.test.js` — HTML/文本/CRA/PDF 格式断言
|
|
615
|
+
- `test/cve-2026-48710-badhost/manifest.test.js` — 13 个 Python 清单解析测试(requirements.txt, pyproject.toml, poetry.lock, 版本边界情况)
|
|
616
|
+
- `test/cve-2026-48710-badhost/transitive.test.js` — 7 个传递性依赖测试(Tier 1/2, fastapi 版本门控, 固定版本抑制)
|
|
617
|
+
- `test/cve-2026-48710-badhost/codePattern.test.js` — 6 个静态代码模式测试(auth 上下文, INFO 穿透, scope 抑制)
|
|
618
|
+
- `test/cve-2026-48710-badhost/integration.test.js` — 4 个集成测试(端到端复合发现项, 清洁项目, 无 Python 文件)
|
|
614
619
|
- `test/cli.test.js` — commander 集成测试(帮助、版本、扫描、报告、错误处理)
|
|
615
620
|
|
|
616
621
|
### 需要帮助?
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { codePatternAuthFinding, codePatternInfoFinding } from './findings.js';
|
|
2
|
+
|
|
3
|
+
const AUTH_CONTEXT_PATHS = [
|
|
4
|
+
'middleware',
|
|
5
|
+
'auth',
|
|
6
|
+
'security',
|
|
7
|
+
'router',
|
|
8
|
+
'depends',
|
|
9
|
+
'guard',
|
|
10
|
+
'permission',
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const URL_PATH_PATTERN = /request\.url\.path|req\.url\.path|self\.request\.url\.path/g;
|
|
14
|
+
const SCOPE_PATH_PATTERN = /request\.scope\s*\[\s*["']path["']\s*\]|request\.scope\.get\s*\(\s*["']path["']\s*\)/g;
|
|
15
|
+
|
|
16
|
+
function hasAuthContext(filePath) {
|
|
17
|
+
const lower = filePath.toLowerCase();
|
|
18
|
+
return AUTH_CONTEXT_PATHS.some(ctx => lower.includes(ctx));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function findFunctionBoundaries(lines) {
|
|
22
|
+
const functions = [];
|
|
23
|
+
let currentFn = null;
|
|
24
|
+
let fnBodyStart = -1;
|
|
25
|
+
let indent = 0;
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < lines.length; i++) {
|
|
28
|
+
const line = lines[i];
|
|
29
|
+
const defMatch = line.match(/^(def\s+\w+|async\s+def\s+\w+)/);
|
|
30
|
+
if (defMatch) {
|
|
31
|
+
if (currentFn) {
|
|
32
|
+
functions.push({ name: currentFn, startLine: fnBodyStart, endLine: i - 1 });
|
|
33
|
+
}
|
|
34
|
+
currentFn = defMatch[1];
|
|
35
|
+
fnBodyStart = i;
|
|
36
|
+
indent = line.length - line.trimStart().length;
|
|
37
|
+
} else if (currentFn && line.trim() && line.length - line.trimStart().length <= indent && !line.trim().startsWith('#') && !line.trim().startsWith('@')) {
|
|
38
|
+
functions.push({ name: currentFn, startLine: fnBodyStart, endLine: i - 1 });
|
|
39
|
+
currentFn = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (currentFn) {
|
|
43
|
+
functions.push({ name: currentFn, startLine: fnBodyStart, endLine: lines.length - 1 });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return functions;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function hasScopePathInFunction(lines, fnStart, fnEnd) {
|
|
50
|
+
for (let i = fnStart; i <= fnEnd && i < lines.length; i++) {
|
|
51
|
+
if (SCOPE_PATH_PATTERN.test(lines[i])) return true;
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function scanCodePatterns(allFiles) {
|
|
57
|
+
const findings = [];
|
|
58
|
+
|
|
59
|
+
for (const file of (allFiles || [])) {
|
|
60
|
+
const content = typeof file.content === 'string' ? file.content : '';
|
|
61
|
+
if (!content) continue;
|
|
62
|
+
const path = file.path || '';
|
|
63
|
+
if (!path.endsWith('.py')) continue;
|
|
64
|
+
|
|
65
|
+
const lines = content.split('\n');
|
|
66
|
+
const isAuthContext = hasAuthContext(path);
|
|
67
|
+
const functions = findFunctionBoundaries(lines);
|
|
68
|
+
const suppressedLines = new Set();
|
|
69
|
+
|
|
70
|
+
for (const fn of functions) {
|
|
71
|
+
if (hasScopePathInFunction(lines, fn.startLine, fn.endLine)) {
|
|
72
|
+
for (let i = fn.startLine; i <= fn.endLine && i < lines.length; i++) {
|
|
73
|
+
if (URL_PATH_PATTERN.test(lines[i])) {
|
|
74
|
+
suppressedLines.add(i + 1);
|
|
75
|
+
}
|
|
76
|
+
URL_PATH_PATTERN.lastIndex = 0;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isAuthContext) {
|
|
82
|
+
let m;
|
|
83
|
+
while ((m = URL_PATH_PATTERN.exec(content)) !== null) {
|
|
84
|
+
const lineNumber = content.slice(0, m.index).split('\n').length;
|
|
85
|
+
if (suppressedLines.has(lineNumber)) continue;
|
|
86
|
+
findings.push(codePatternAuthFinding(path, lineNumber));
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
let m;
|
|
90
|
+
while ((m = URL_PATH_PATTERN.exec(content)) !== null) {
|
|
91
|
+
const lineNumber = content.slice(0, m.index).split('\n').length;
|
|
92
|
+
if (suppressedLines.has(lineNumber)) continue;
|
|
93
|
+
findings.push(codePatternInfoFinding(path, lineNumber));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return findings;
|
|
99
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const CVE = 'CVE-2026-48710';
|
|
2
|
+
const NICKNAME = 'BadHost';
|
|
3
|
+
const CVSS = 7.0;
|
|
4
|
+
const REFERENCES = [
|
|
5
|
+
'https://ostif.org/disclosing-the-badhost-vulnerability-in-starlette/',
|
|
6
|
+
'https://github.com/Kludex/starlette/security/advisories/GHSA-86qp-5c8j-p5mr',
|
|
7
|
+
'https://badhost.org/',
|
|
8
|
+
'https://osv.dev/vulnerability/PYSEC-2026-161',
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const MITIGATION_NOTE = 'Partial mitigation: Cloudflare and AWS ALB reject malformed Host headers for properly proxied deployments. Direct uvicorn/hypercorn/daphne/granian exposure with no reverse proxy in front is highest risk.';
|
|
12
|
+
|
|
13
|
+
const DEPENDENCY_REMEDIATION = 'Upgrade starlette to >= 1.0.1. If starlette is inherited transitively through fastapi, vllm, litellm, or an MCP server package, upgrade the top-level package to a version that pins starlette >= 1.0.1. Verify with: pip show starlette.';
|
|
14
|
+
|
|
15
|
+
const CODE_REMEDIATION = 'Replace request.url.path with request.scope["path"] for all security-sensitive decisions (auth checks, path allowlists, rate limiting gates). The reconstructed request.url is influenced by the unvalidated Host header in Starlette < 1.0.1.';
|
|
16
|
+
|
|
17
|
+
function makeFinding(overrides = {}) {
|
|
18
|
+
return {
|
|
19
|
+
id: CVE,
|
|
20
|
+
severity: 'high',
|
|
21
|
+
title: `${NICKNAME} — ${overrides.source || 'unknown'}`,
|
|
22
|
+
description: '',
|
|
23
|
+
remediation: '',
|
|
24
|
+
evidence: JSON.stringify({
|
|
25
|
+
cve: CVE,
|
|
26
|
+
nickname: NICKNAME,
|
|
27
|
+
cvss: CVSS,
|
|
28
|
+
references: REFERENCES,
|
|
29
|
+
...overrides,
|
|
30
|
+
}),
|
|
31
|
+
...overrides,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function directDependencyFinding(version, specifier) {
|
|
36
|
+
return makeFinding({
|
|
37
|
+
severity: 'high',
|
|
38
|
+
confidence: 'HIGH',
|
|
39
|
+
source: 'direct-dependency',
|
|
40
|
+
title: `${NICKNAME}: Starlette ${version} vulnerable`,
|
|
41
|
+
description: `Starlette ${version} (${specifier}) is vulnerable to CVE-2026-48710 (BadHost) — authentication bypass via Host header injection. Upgrade to starlette >= 1.0.1.`,
|
|
42
|
+
remediation: `${DEPENDENCY_REMEDIATION} ${MITIGATION_NOTE}`,
|
|
43
|
+
file: null,
|
|
44
|
+
line: null,
|
|
45
|
+
via: null,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function directDependencyUnpinnedFinding() {
|
|
50
|
+
return makeFinding({
|
|
51
|
+
severity: 'high',
|
|
52
|
+
confidence: 'HIGH',
|
|
53
|
+
source: 'direct-dependency-unpinned',
|
|
54
|
+
title: `${NICKNAME}: Starlette unpinned`,
|
|
55
|
+
description: 'Starlette is declared with no version constraint — assume vulnerable to CVE-2026-48710 (BadHost) until pinned to >= 1.0.1.',
|
|
56
|
+
remediation: `${DEPENDENCY_REMEDIATION} ${MITIGATION_NOTE}`,
|
|
57
|
+
file: null,
|
|
58
|
+
line: null,
|
|
59
|
+
via: null,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function transitiveDependencyFinding(packageName, tier) {
|
|
64
|
+
const confidence = tier === 1 ? 'HIGH' : 'MEDIUM';
|
|
65
|
+
const tierLabel = tier === 1 ? 'Tier 1' : 'Tier 2';
|
|
66
|
+
return makeFinding({
|
|
67
|
+
severity: 'high',
|
|
68
|
+
confidence,
|
|
69
|
+
source: 'transitive-dependency',
|
|
70
|
+
title: `${NICKNAME}: Transitive via ${packageName}`,
|
|
71
|
+
description: `Starlette not directly pinned; inherited through ${packageName} (${tierLabel}). ${packageName} depends on Starlette — if its version constraint allows Starlette < 1.0.1, your deployment is vulnerable.`,
|
|
72
|
+
remediation: `${DEPENDENCY_REMEDIATION} ${MITIGATION_NOTE}`,
|
|
73
|
+
file: null,
|
|
74
|
+
line: null,
|
|
75
|
+
via: packageName,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function codePatternAuthFinding(filePath, lineNumber) {
|
|
80
|
+
return makeFinding({
|
|
81
|
+
severity: 'medium',
|
|
82
|
+
confidence: 'MEDIUM',
|
|
83
|
+
source: 'code-pattern',
|
|
84
|
+
title: `${NICKNAME}: Dangerous path extraction in auth/middleware`,
|
|
85
|
+
description: `request.url.path used in auth/middleware context at ${filePath}:${lineNumber} — use request.scope['path'] instead. The reconstructed request.url is influenced by the unvalidated Host header in Starlette < 1.0.1.`,
|
|
86
|
+
remediation: `${CODE_REMEDIATION} ${MITIGATION_NOTE}`,
|
|
87
|
+
file: filePath,
|
|
88
|
+
line: lineNumber,
|
|
89
|
+
via: null,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function codePatternInfoFinding(filePath, lineNumber) {
|
|
94
|
+
return makeFinding({
|
|
95
|
+
severity: 'info',
|
|
96
|
+
confidence: 'LOW',
|
|
97
|
+
source: 'code-pattern',
|
|
98
|
+
title: `${NICKNAME}: request.url.path usage detected`,
|
|
99
|
+
description: `request.url.path used at ${filePath}:${lineNumber} — may be influenced by unvalidated Host header in Starlette < 1.0.1. Verify request.scope['path'] is used for security decisions.`,
|
|
100
|
+
remediation: `${CODE_REMEDIATION} ${MITIGATION_NOTE}`,
|
|
101
|
+
file: filePath,
|
|
102
|
+
line: lineNumber,
|
|
103
|
+
via: null,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { scanFiles } from './manifest.js';
|
|
2
|
+
import { scanTransitive } from './transitive.js';
|
|
3
|
+
import { scanCodePatterns } from './codePattern.js';
|
|
4
|
+
|
|
5
|
+
export async function scan(pkgJson, files = [], registryMeta = null, allFiles = null) {
|
|
6
|
+
const targetFiles = allFiles || files;
|
|
7
|
+
|
|
8
|
+
const manifestFindings = scanFiles(targetFiles);
|
|
9
|
+
const transitiveFindings = scanTransitive(targetFiles);
|
|
10
|
+
const codeFindings = scanCodePatterns(targetFiles);
|
|
11
|
+
|
|
12
|
+
const allFindings = [...manifestFindings, ...transitiveFindings, ...codeFindings];
|
|
13
|
+
|
|
14
|
+
return allFindings;
|
|
15
|
+
}
|