@lateos/npm-scan 0.16.0 β†’ 0.16.5

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.
Files changed (110) hide show
  1. package/.dockerignore +20 -20
  2. package/.husky/pre-commit +1 -1
  3. package/CHANGELOG.md +199 -199
  4. package/LICENSING.md +19 -19
  5. package/README.de.md +708 -669
  6. package/README.fr.md +707 -668
  7. package/README.ja.md +704 -665
  8. package/README.md +826 -801
  9. package/README.zh.md +708 -669
  10. package/SECURITY.md +72 -72
  11. package/backend/cra.js +68 -68
  12. package/backend/db/schema.sql +32 -32
  13. package/backend/db.js +88 -88
  14. package/backend/detectors/atk-001-lifecycle.js +17 -17
  15. package/backend/detectors/atk-002-obfusc.js +261 -261
  16. package/backend/detectors/atk-003-creds.js +13 -13
  17. package/backend/detectors/atk-004-persist.js +13 -13
  18. package/backend/detectors/atk-005-exfil.js +13 -13
  19. package/backend/detectors/atk-006-depconf.js +14 -14
  20. package/backend/detectors/atk-007-typosquat.js +34 -34
  21. package/backend/detectors/atk-008-tarball-tamper.js +91 -91
  22. package/backend/detectors/atk-009-dormant-trigger.js +62 -62
  23. package/backend/detectors/atk-010-sandbox-evasion.js +50 -50
  24. package/backend/detectors/atk-011-transitive-prop.js +76 -76
  25. package/backend/detectors/axios-poisoning/d1-version-fingerprint.js +24 -0
  26. package/backend/detectors/axios-poisoning/d2-decoy-dep.js +24 -0
  27. package/backend/detectors/axios-poisoning/d3-postinstall-rat.js +90 -0
  28. package/backend/detectors/axios-poisoning/index.js +94 -0
  29. package/backend/detectors/cve-2026-48710-badhost/codePattern.js +99 -99
  30. package/backend/detectors/cve-2026-48710-badhost/findings.js +105 -105
  31. package/backend/detectors/cve-2026-48710-badhost/index.js +15 -15
  32. package/backend/detectors/cve-2026-48710-badhost/manifest.js +305 -305
  33. package/backend/detectors/cve-2026-48710-badhost/transitive.js +189 -189
  34. package/backend/detectors/hf-impersonation/index.js +396 -396
  35. package/backend/detectors/hf-impersonation/jaro-winkler.js +44 -44
  36. package/backend/detectors/hf-impersonation/known-orgs.js +5 -5
  37. package/backend/detectors/hf-impersonation/simhash.js +46 -46
  38. package/backend/detectors/index.js +75 -38
  39. package/backend/detectors/megalodon/d1-workflow-scan.js +147 -147
  40. package/backend/detectors/megalodon/d2-credential-harvest.js +61 -61
  41. package/backend/detectors/megalodon/d3-publish-velocity.js +67 -67
  42. package/backend/detectors/megalodon/d4-publisher-drift.js +124 -124
  43. package/backend/detectors/megalodon/d5-bot-commit-identity.js +3 -3
  44. package/backend/detectors/megalodon/d6-date-anachronism.js +3 -3
  45. package/backend/detectors/megalodon/index.js +80 -80
  46. package/backend/detectors/megalodon/types.js +9 -9
  47. package/backend/detectors/mini-shai-hulud/d1-burst-publish.js +42 -42
  48. package/backend/detectors/mini-shai-hulud/d2-sibling-compromise.js +116 -116
  49. package/backend/detectors/mini-shai-hulud/d3-slsa-mismatch.js +72 -72
  50. package/backend/detectors/mini-shai-hulud/d4-maintainer-anomaly.js +45 -45
  51. package/backend/detectors/mini-shai-hulud/d5-ioc-check.js +95 -95
  52. package/backend/detectors/mini-shai-hulud/d6-token-exfil.js +38 -38
  53. package/backend/detectors/mini-shai-hulud/index.js +118 -118
  54. package/backend/detectors/mini-shai-hulud/iocs.json +79 -79
  55. package/backend/detectors/msh-supplement/d1-obfuscation.js +18 -0
  56. package/backend/detectors/msh-supplement/d2-persistence.js +47 -0
  57. package/backend/detectors/msh-supplement/d3-geo-killswitch.js +35 -0
  58. package/backend/detectors/msh-supplement/d4-c2-deaddrop.js +33 -0
  59. package/backend/detectors/msh-supplement/index.js +107 -0
  60. package/backend/detectors/tier1-binary-embed.js +219 -0
  61. package/backend/detectors/tier1-infostealer.js +280 -0
  62. package/backend/detectors/tier1-lifecycle-hook.js +176 -0
  63. package/backend/detectors/tier1-metadata-spoof.js +180 -0
  64. package/backend/detectors/tier1-typosquat.js +219 -0
  65. package/backend/detectors/typosquat-vpmdhaj/d1-maintainer.js +77 -0
  66. package/backend/detectors/typosquat-vpmdhaj/d2-preinstall-loader.js +37 -0
  67. package/backend/detectors/typosquat-vpmdhaj/d3-cred-exfil.js +66 -0
  68. package/backend/detectors/typosquat-vpmdhaj/index.js +98 -0
  69. package/backend/fetch.js +175 -175
  70. package/backend/index.js +4 -4
  71. package/backend/license.js +89 -89
  72. package/backend/lockfile.js +379 -379
  73. package/backend/pdf.js +245 -245
  74. package/backend/policy.js +193 -176
  75. package/backend/provenance.js +79 -0
  76. package/backend/report.js +254 -254
  77. package/backend/sbom.js +66 -66
  78. package/backend/siem/cef.js +32 -32
  79. package/backend/siem/ecs.js +40 -40
  80. package/backend/siem/index.js +18 -18
  81. package/backend/siem/qradar.js +56 -56
  82. package/backend/siem/sentinel.js +27 -27
  83. package/backend/vsix-scan/detectors/activation-event-risk.js +116 -116
  84. package/backend/vsix-scan/detectors/burst-publish.js +52 -52
  85. package/backend/vsix-scan/detectors/exfil-pattern.js +88 -88
  86. package/backend/vsix-scan/detectors/known-ioc.js +105 -105
  87. package/backend/vsix-scan/detectors/orphan-commit-fetch.js +69 -69
  88. package/backend/vsix-scan/detectors/publisher-anomaly.js +70 -70
  89. package/backend/vsix-scan/index.js +183 -183
  90. package/backend/vsix-scan/marketplace-client.js +145 -145
  91. package/backend/vsix-scan/vsix-iocs.json +31 -31
  92. package/cli/cli.js +458 -458
  93. package/deploy/helm/npm-scan/Chart.yaml +21 -21
  94. package/deploy/helm/npm-scan/templates/_helpers.tpl +8 -8
  95. package/deploy/helm/npm-scan/templates/api.yaml +93 -93
  96. package/deploy/helm/npm-scan/templates/ingress.yaml +27 -27
  97. package/deploy/helm/npm-scan/templates/postgresql.yaml +66 -66
  98. package/deploy/helm/npm-scan/templates/secrets.yaml +18 -18
  99. package/deploy/helm/npm-scan/templates/worker.yaml +31 -31
  100. package/deploy/helm/npm-scan/values.byoc.yaml +74 -74
  101. package/deploy/helm/npm-scan/values.yaml +102 -102
  102. package/package.json +57 -57
  103. package/scripts/download-corpus.js +30 -30
  104. package/scripts/gen-mal-corpus.js +34 -34
  105. package/scripts/generate-campaign-fixtures.js +170 -0
  106. package/src/config/top-5000.json +87 -0
  107. package/test/fixtures/lockfiles/npm-lock.json +68 -68
  108. package/test/fixtures/lockfiles/pnpm-lock.yaml +117 -117
  109. package/test/fixtures/lockfiles/yarn.lock +103 -103
  110. package/test/fixtures/mock-data.js +69 -69
package/README.md CHANGED
@@ -1,801 +1,826 @@
1
- # @lateos/npm-scan
2
-
3
- [![npm version](https://img.shields.io/npm/v/@lateos/npm-scan?style=flat-square)](https://www.npmjs.com/package/@lateos/npm-scan)
4
- [![License](https://img.shields.io/badge/license-Apache%202.0%20%2B%20Commons%20Clause-blue?style=flat-square)](LICENSING.md)
5
- [![Node](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](package.json)
6
- [![Tests](https://img.shields.io/badge/tests-536%20passing-brightgreen?style=flat-square)](https://github.com/lateos-ai/npm-scan)
7
- [![Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen?style=flat-square)](https://github.com/lateos-ai/npm-scan)
8
- [![Docker](https://img.shields.io/badge/docker-lateos%2Fnpm--scan-2496ED?style=flat-square&logo=docker)](https://hub.docker.com/r/lateos/npm-scan)
9
- [![Sigstore](https://img.shields.io/static/v1?label=Sigstore&message=Provenance&color=green&style=flat-square&logo=sigstore)](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
10
-
11
- [![δΈ­ζ–‡](https://img.shields.io/badge/lang-zh--CN-red?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.zh.md)
12
- [![ζ—₯本θͺž](https://img.shields.io/badge/lang-ja-purple?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.ja.md)
13
- [![FranΓ§ais](https://img.shields.io/badge/lang-fr-orange?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.fr.md)
14
- [![Deutsch](https://img.shields.io/badge/lang-de-green?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.de.md)
15
-
16
- **Modern supply chain security for the npm ecosystem.**
17
- Static + behavioral analysis that catches what npm audit, Snyk, and Socket miss β€” obfuscated payloads, credential stealers, conditional triggers, sandbox evasion, and worm-like propagation.
18
-
19
- ---
20
-
21
- ## πŸ“Œ The Problem
22
-
23
- The 2025–2026 wave of npm supply chain attacks proved that traditional tooling is no longer enough.
24
-
25
- Attackers have moved past simple typosquatting. They now ship **obfuscated preinstall hooks**, **credential harvesters hidden behind environment detection**, **dormant backdoors with time-based activation**, and **worm-style transitive propagation** that spreads through peer dependencies.
26
-
27
- A growing attack vector is **HuggingFace org impersonation** β€” packages that masquerade as legitimate HF model repositories (e.g., `0penai/gpt2` instead of `openai/gpt2`) to trick users into downloading malicious model artifacts during CI/CD pipelines, often bundled with suspicious binaries (`.exe`, `.dll`) in model repos that deep-learned tools trust by default.
28
-
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
-
31
- The **TrapDoor campaign** (May 2026) spans npm, PyPI, and Crates.io β€” 34 malicious packages, 384+ versions attributed to a single publisher, targeting crypto, DeFi, Solana, and AI developers with Fernet + ECDH encrypted payloads, AI context poisoning via zero-width Unicode injection in `.cursorrules`/`CLAUDE.md`, and credential live-validation against AWS STS and GitHub API before exfiltration. **@lateos/npm-scan** now detects all 9 TrapDoor signals.
32
-
33
- The **node-ipc compromise** (May 14, 2026) weaponized an expired maintainer email domain to hijack one of npm's most depended-upon packages (822K weekly downloads). Three malicious versions (9.1.6, 9.2.3, 12.0.1) delivered an 80KB credential stealer via DNS TXT tunneling β€” no HTTP, no postinstall hook, invisible to HTTP-layer firewalls. **@lateos/npm-scan** now detects all 11 node-ipc compromise signals.
34
-
35
- 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.
36
-
37
- **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.
38
-
39
- **@lateos/npm-scan** was built for this moment.
40
-
41
- ---
42
-
43
- ## πŸ”¬ Why @lateos/npm-scan?
44
-
45
- | Capability | npm audit | Snyk | Socket | **@lateos/npm-scan** |
46
- |---|---|---|---|---|
47
- | Known CVE matching | βœ… | βœ… | ❌ | βœ… |
48
- | Static analysis | ❌ | βœ… | βœ… | βœ… |
49
- | Obfuscated payload detection | ❌ | ❌ | ❌ | βœ… |
50
- | AST-level heuristic analysis | ❌ | ❌ | ❌ | βœ… |
51
- | Runtime behavioral sandbox | ❌ | ❌ | βœ… | βœ… |
52
- | Conditional trigger detection (ATK-009) | ❌ | ❌ | ❌ | βœ… |
53
- | Sandbox evasion detection (ATK-010) | ❌ | ❌ | ❌ | βœ… |
54
- | Transitive worm propagation (ATK-011) | ❌ | ❌ | ❌ | βœ… |
55
- | Campaign detection (Megalodon CI/CD) | ❌ | ❌ | ❌ | βœ… |
56
- | Worm campaign detection (Mini Shai-Hulud Wave 1–3) | ❌ | ❌ | ❌ | βœ… |
57
- | HF model repo impersonation + README clone | ❌ | ❌ | ❌ | βœ… |
58
- | VS Code extension supply chain scan (--vsix) | ❌ | ❌ | ❌ | βœ… |
59
- | Python vulnerability detection (CVE-2026-48710 BadHost) | ❌ | ❌ | ❌ | βœ… |
60
- | Cross-ecosystem attack detection (TrapDoor) | ❌ | ❌ | ❌ | βœ… |
61
- | Expired-domain hijack detection (node-ipc) | ❌ | ❌ | ❌ | βœ… |
62
- | Attack taxonomy (ATK series) | ❌ | ❌ | ❌ | βœ… |
63
- | SBOM output (CycloneDX + SPDX) | ❌ | βœ… | ❌ | βœ… |
64
- | SARIF v2.1 (GitHub Code Scanning) | ❌ | ❌ | ❌ | βœ… |
65
- | NIST 800-161 compliance reporting | ❌ | ❌ | ❌ | βœ… |
66
- | EU CRA compliance reporting | ❌ | ❌ | ❌ | βœ… |
67
- | SIEM export (CEF / ECS / Sentinel / QRadar) | ❌ | ❌ | ❌ | βœ… |
68
- | Runs entirely locally β€” no telemetry | βœ… | ❌ | ❌ | βœ… |
69
- | Policy-as-code (YAML allowlists) | ❌ | ❌ | ❌ | βœ… |
70
-
71
- > **Privacy first.** All scanning happens on your machine. No code leaves your environment. No telemetry. No cloud dependency.
72
-
73
- ---
74
-
75
- ## ✨ Key Features
76
-
77
- | Icon | Feature | Description |
78
- |------|---------|-------------|
79
- | πŸ•΅οΈ | **Heuristic static analysis** | AST-level inspection catches obfuscation, eval chains, env probing, and suspicious lifecycle scripts that regex-based tools miss |
80
- | 🧠 | **Behavioral detection** | Identifies conditional triggers (time-based, CI-aware), sandbox evasion, and dormant activation patterns |
81
- | 🧬 | **ATK attack taxonomy** | 11 classified attack types with NIST 800-161 mappings β€” versioned, documented, and PR-able |
82
- | πŸͺ± | **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) |
83
- | 🧩 | **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) |
84
- | 🐍 | **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 |
85
- | πŸͺ€ | **Cross-ecosystem attack detection** | TrapDoor β€” 9 sub-checks: campaign marker P-2024-001, trap-core.js payload fingerprint, publisher blocklist asdxzxc, Gist-based credential exfil, AI config zero-width Unicode poisoning, crypto/DeFi lure name heuristic, Fernet+ECDH encryption, XOR key cargo-build-helper-2026, STS/GitHub API credential validation |
86
- | πŸ“‘ | **Expired-domain hijack detection** | node-ipc compromise β€” version blocklist (9.1.6/9.2.3/12.0.1), tarball SHA-256 verification, CJS vs ESM size anomaly with IIFE injection, DNS-over-non-standard-port C2, bootstrap resolver sh.azurestaticprovider.net, DNS TXT exfil zone bt.node.js, setImmediate() runtime trigger, ~/nt-*/ staging artifacts, unauthorized publisher atiertant, lockfile blast-radius with safe pin recommendations |
87
- | πŸ“¦ | **SBOM generation** | CycloneDX 1.5 and SPDX 2.3 with findings embedded as vulnerabilities |
88
- | πŸ” | **SARIF output** | GitHub Advanced Security / CodeQL compatible SARIF v2.1 β€” shows findings directly in Security tab |
89
- | 🧾 | **Compliance reporting** | NIST SP 800-161 traceability matrix + EU Cyber Resilience Act mapping (free tier) |
90
- | πŸ”Œ | **SIEM export** | Splunk CEF, Elastic ECS, Microsoft Sentinel, IBM QRadar formats (premium) |
91
- | πŸ“œ | **Policy-as-code** | YAML/JSON policy engine with allowlists, severity overrides, suppressions, and fail-on thresholds |
92
- | 🐳 | **Docker + GitHub Action** | Multi-arch images, one-command Compose pipeline, PR scan action |
93
- | πŸ›‘οΈ | **Zero telemetry** | No data leaves your machine. No cloud. No callbacks. |
94
- | πŸ’Ύ | **Local scan history** | SQLite-backed persistence, zero external dependencies |
95
- | πŸͺ | **Pre-commit hook** | Block threats before commit β€” one-liner install, scans `package-lock.json` changes |
96
- | πŸ€– | **HF impersonation detection** | Detects typosquatted HuggingFace orgs (Jaro-Winkler), README clones (SimHash), artifact mismatches (`.exe` in model repos), and new-org amplifier β€” with lazy two-stage evaluation, zero network in Stage 1 |
97
- | πŸ“Ž | **Yarn + pnpm support** | `scan-lockfile` parses `yarn.lock` and `pnpm-lock.yaml` alongside `package-lock.json` |
98
-
99
- ---
100
-
101
- ## ⚑ Quick Start
102
-
103
- ```bash
104
- # Install globally
105
- npm install -g @lateos/npm-scan
106
-
107
- # Scan a single package
108
- npm-scan scan lodash
109
-
110
- # Scan your lockfile
111
- npm-scan scan-lockfile
112
-
113
- # View latest scans
114
- npm-scan report
115
- ```
116
-
117
- **No install? No problem:**
118
-
119
- ```bash
120
- npx @lateos/npm-scan scan commander
121
- ```
122
-
123
- ---
124
-
125
- ## 🐳 Run @lateos/npm-scan anywhere with Docker β€” zero installation
126
-
127
- ```bash
128
- # Pull and run a single scan β€” no Node.js or npm required
129
- docker run --rm lateos/npm-scan:cli scan lodash
130
-
131
- # Full pipeline with persistent storage and Compose
132
- docker compose --profile pipeline up -d
133
- ```
134
-
135
- No Node.js. No `npm install`. No global packages. Works on any system with Docker β€” CI servers, air-gapped environments, Kubernetes clusters. Multi-arch images for `linux/amd64` and `linux/arm64`.
136
-
137
- ---
138
-
139
- ## πŸ›‘οΈ Government & SOC 2 Ready
140
-
141
- | Feature | SOC 2 Controls | NIST 800-161 | STIG/FedRAMP Alignment |
142
- |---------|-------|--------------|--------------|
143
- | Audit logs (--audit-log) | CC6.8 | AU-2 | βœ“ |
144
- | FIPS crypto (--fips) | CC6.1 | SC-13 | βœ“ |
145
- | STIG report (--stig) | CC7.3 | RA-5 | βœ“ |
146
- | Offline cache (--cache-dir) | A1.2 | SC-8 | βœ“ |
147
- | Sigstore provenance | CC6.2 | SI-7 | βœ“ |
148
- | SBOM (SPDX/CycloneDX) | CC7.4 | SA-10 | βœ“ |
149
-
150
- ```bash
151
- # Air-gapped scan with full compliance
152
- npm-scan scan-lockfile --cache-dir /offline/cache --audit-log /var/log/npm-scan.audit --fips
153
- npm-scan report --stig
154
- ```
155
-
156
- [![SOC 2 Ready](https://img.shields.io/badge/SOC%202-Ready-green?style=flat-square&logo=aicpa)](https://www.aicpa.org/interestareas/frc/assuranceadvisoryservices/sorhome.html#soc2)
157
- [![FedRAMP Aligned](https://img.shields.io/badge/FedRAMP-Aligned-blue?style=flat-square&logo=fedramp)](https://fedramp.gov/baselines/)
158
-
159
- ---
160
-
161
- ## ☁️ BYOC β€” Bring Your Own Cloud
162
-
163
- Deploy npm-scan in your VPC with full data sovereignty. No data leaves your infrastructure.
164
-
165
- | Feature | Description |
166
- |---------|-------------|
167
- | **Self-hosted** | Run on EKS/GKE/AKS in your AWS/Azure/GCP account |
168
- | **SIEM Export** | CEF/ECS/Sentinel/QRadar to your existing SIEM |
169
- | **SSO/OIDC** | SAML/OIDC integration with your identity provider |
170
- | **PDF Reports** | Generate NIST-compliant PDF reports locally |
171
- | **External DB** | Connect to your existing PostgreSQL/Redis |
172
-
173
- ```bash
174
- # Deploy to your VPC with Helm
175
- git clone https://github.com/lateos-ai/npm-scan.git
176
- cd npm-scan/deploy/helm
177
- helm install npm-scan -f values.byoc.yaml .
178
-
179
- # BYOC values example (see values.byoc.yaml)
180
- premium:
181
- enabled: true
182
- edition: enterprise
183
- byoc:
184
- enabled: true
185
- cloudProvider: aws
186
- vpcId: vpc-xxx
187
- region: us-east-1
188
- ```
189
-
190
- **Pricing**: Enterprise license $10k/yr β€” self-supported (docs + GitHub issues).
191
-
192
- ---
193
-
194
- ## πŸ“– Usage Examples
195
-
196
- ### Scan a single package
197
-
198
- ```bash
199
- # Default JSON output with all findings
200
- npm-scan scan axios
201
-
202
- # Generate an SBOM alongside the scan
203
- npm-scan scan express --sbom # CycloneDX JSON
204
- npm-scan scan express --sbom xml # CycloneDX XML
205
- npm-scan scan express --sbom spdx # SPDX 2.3
206
-
207
- # Apply a YAML policy
208
- npm-scan scan some-package --policy .npm-scan.yml
209
-
210
- # Scan a local tarball (no registry fetch needed)
211
- npm-scan scan --file path/to/malicious-package.tgz
212
-
213
- # Scan a VS Code extension for Marketplace supply chain attacks
214
- npm-scan scan --vsix nrwl.angular-console
215
-
216
- # Scan a package AND a VSIX extension together (findings merge)
217
- npm-scan scan lodash --vsix nrwl.angular-console
218
- ```
219
-
220
- ### Scan a lockfile
221
-
222
- ```bash
223
- # Scan a single package
224
- npm-scan scan lodash
225
-
226
- # Scan your lockfile
227
- npm-scan scan-lockfile
228
-
229
- # Scan a VS Code extension for supply chain threats
230
- npm-scan scan --vsix nrwl.angular-console
231
-
232
- # View latest scans
233
- npm-scan report
234
- ```
235
-
236
- ### Generate reports
237
-
238
- ```bash
239
- # List all recent scans
240
- npm-scan report
241
-
242
- # View a specific scan
243
- npm-scan report -i 42
244
-
245
- # Generate an HTML report (free) with full findings + NIST table
246
- npm-scan report -i 42 --html
247
-
248
- # Print NIST 800-161 compliance table
249
- npm-scan report -i 42 --nist
250
-
251
- # Print EU CRA compliance table
252
- npm-scan report --cra
253
-
254
- # CSV export for Excel / Sheets (audit-ready)
255
- npm-scan report --csv risks.csv
256
- npm-scan scan lodash --csv # CSV to stdout
257
-
258
- # Text report (free)
259
- npm-scan report --text
260
-
261
- # PDF report (premium)
262
- npm-scan report --pdf --license-key <key>
263
-
264
- # SIEM export (premium)
265
- npm-scan report --siem cef # Splunk CEF
266
- npm-scan report --siem ecs # Elastic ECS
267
- npm-scan report --siem sentinel # Microsoft Sentinel
268
- npm-scan report --siem qradar # IBM QRadar
269
-
270
- # Combine all scans into a single report
271
- npm-scan report --html # all scans
272
- npm-scan report --pdf # all scans (premium)
273
- ```
274
-
275
- ---
276
-
277
- ## 🧬 Detection Capabilities (ATK Taxonomy)
278
-
279
- | ID | Attack Class | Detection Method | Severity | NIST 800-161 |
280
- |---|---|---|---|---|
281
- | **ATK-001** | Malicious lifecycle scripts (`preinstall`, `postinstall`, `install`) | Static | πŸ”΄ high | SR-3.1 |
282
- | **ATK-002** | Obfuscated payload delivery (hex, base64, eval chains) | Static | 🟠 medium | SR-4.2 |
283
- | **ATK-003** | Credential harvesting (env vars, .npmrc, SSH keys) | Static + Dynamic | πŸ”΄ high | SR-5.3 |
284
- | **ATK-004** | Persistence via editor/config dirs (.vscode, .claude, .cursor) | Static | πŸ”΄ high | SR-6.4 |
285
- | **ATK-005** | Network exfiltration (GitHub API, DNS tunneling, HTTP C2) | Static + Dynamic | ⚫ critical | SR-7.5 |
286
- | **ATK-006** | Dependency confusion / namespace squatting | Static (lockfile) | 🟠 medium | SR-2.2 |
287
- | **ATK-007** | Typosquatting (edit-distance matching) | Static | 🟒 low | SR-2.1 |
288
- | **ATK-008** | Tarball tampering (published β‰  source) | Static | πŸ”΄ high | SR-8.1 |
289
- | **ATK-009** | Conditional/dormant triggers (CI detection, time-based) | Behavioral | πŸ”΄ high | SR-9.2 |
290
- | **ATK-010** | Sandbox evasion / anti-analysis | Behavioral | 🟠 medium | SR-10.3 |
291
- | **ATK-011** | Transitive propagation (worm-style lateral spread) | Behavioral | πŸ”΄ high | SR-11.4 |
292
- | **MEGALODON** | Megalodon CI/CD campaign β€” workflow C2 exfil, credential harvest, publish velocity spike, publisher drift | Static + Registry | ⚫ critical | SR-3.1, SR-7.5 |
293
- | **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 |
294
- | **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 |
295
- | **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 |
296
- | **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 |
297
- | **TRAPDOOR** | TrapDoor cross-ecosystem attack β€” campaign marker P-2024-001 in files, shared payload trap-core.js filename/48,485-byte fingerprint, publisher blocklist asdxzxc, Gist-based credential exfil (ddjidd564.github.io + credential paths), AI context poisoning via zero-width Unicode in .cursorrules/CLAUDE.md, crypto/DeFi lure name heuristic (<30 days), Fernet+ECDH crypto primitives in postinstall, XOR key cargo-build-helper-2026 in lockfiles, STS/GitHub API credential validation in postinstall | Static + Registry | 🟠 medium / πŸ”΄ high / ⚫ critical | SR-3.1, SR-5.3, SR-7.5 |
298
- | **NODE_IPC_COMPROMISE** | node-ipc supply chain compromise (May 14, 2026) β€” version blocklist (9.1.6/9.2.3/12.0.1) with safe pins, tarball SHA-256 verification, CJS payload IIFE injection detection (CJS>ESM size differential), injected payload hash match, DNS-over-non-standard-port C2 (setServers + custom resolver), bootstrap resolver sh.azurestaticprovider.net + C2 IP 37.16.75.69, DNS TXT exfiltration zone bt.node.js, setImmediate() runtime trigger, ~/nt-*/ staging artifact detection, unauthorized publisher atiertant, lockfile blast-radius detection with pin recommendations | Static + Registry | ⚫ critical | SR-3.1, SR-5.3, SR-7.5 |
299
-
300
- > **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.
301
- > **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.
302
- > **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.
303
- > **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`.
304
- > **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.
305
- > **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.
306
- > **TRAPDOOR** campaign detection runs 9 sub-detectors across all package files (README.md, package.json, .md, shell scripts, .cursorrules, CLAUDE.md) for the hardcoded marker P-2024-001, scans for trap-core.js by filename or exact 48,485-byte size, unconditionally blocks publisher asdxzxc, detects outbound references to ddjidd564.github.io or gist.github.com combined with credential-path patterns, scans .cursorrules and CLAUDE.md for zero-width Unicode characters (U+200B, U+200C, U+200D, U+FEFF), flags crypto/DeFi-themed packages <30 days old with no prior version history, detects simultaneous Fernet and ECDH/createECDH usage in postinstall JS, and identifies sts.amazonaws.com and api.github.com/user calls in postinstall hooks.
307
- > **NODE_IPC_COMPROMISE** detection intercepts the expired-domain takeover attack across 11 dimensions: version blocklist with safe-pin recommendations (9.1.5 for 9.x, 12.0.0 for 12.x), tarball SHA-256 hash verification against known malicious hashes, CJS vs ESM size comparison with IIFE suffix pattern detection for injected payload identification, DNS resolver pattern analysis (dns.promises.Resolver + setServers with non-public IP + resolveTxt), bootstrap domain and C2 IP detection, resolveTxt() with bt.node.js zone references, setImmediate() runtime trigger detection, ~/nt-*/ staging artifact path identification, publisher account verification against unauthorized account atiertant, and lockfile scanning for compromised version resolution with safe-pin suggestions.
308
- > See [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md) for full evasion surface documentation and PoC examples.
309
-
310
- ---
311
-
312
- ## πŸ“Š Output & Reports
313
-
314
- ### Formats
315
-
316
- | Format | Availability | Description |
317
- |--------|-------------|-------------|
318
- | JSON | βœ… Free | Structured machine-readable findings |
319
- | HTML | βœ… Free | Rich HTML report with NIST compliance table, severity badges, control matrix |
320
- | Text | βœ… Free | Clean terminal-friendly text report |
321
- | CycloneDX SBOM | βœ… Free | Industry-standard SBOM with findings as vulnerabilities |
322
- | SPDX SBOM | βœ… Free | SPDX 2.3 document format |
323
- | NIST 800-161 | βœ… Free | Control traceability matrix (SR-2.1 β†’ SR-11.4) |
324
- | EU CRA | βœ… Free | Cyber Resilience Act article mapping |
325
- | PDF | πŸ” Premium | Multi-page PDF with title page, findings table, NIST compliance matrix |
326
- | Splunk CEF | πŸ” Premium | Common Event Format for Splunk ingestion |
327
- | Elastic ECS | πŸ” Premium | Elastic Common Schema format |
328
- | Microsoft Sentinel | πŸ” Premium | Sentinel-ready formatted output |
329
- | IBM QRadar | πŸ” Premium | QRadar DSM-ready format with QID mappings |
330
-
331
- ### Sample output
332
-
333
- ```json
334
- {
335
- "scanId": 1,
336
- "findings": [
337
- {
338
- "id": "ATK-003",
339
- "severity": "high",
340
- "title": "Credential harvesting",
341
- "evidence": "process.env.NPM_TOKEN detected in postinstall.js:17"
342
- }
343
- ]
344
- }
345
- ```
346
-
347
- ---
348
-
349
- ## βš™οΈ Configuration & Advanced Usage
350
-
351
- ### Policy-as-code
352
-
353
- Define allowlists, severity overrides, suppressions, and fail thresholds in a YAML file:
354
-
355
- ```yaml
356
- # .npm-scan.yml
357
- allowlist:
358
- - lodash
359
- - chalk
360
-
361
- severity_overrides:
362
- - id: ATK-001
363
- severity: medium
364
-
365
- suppress:
366
- - atk_id: ATK-009
367
- - package: some-package
368
-
369
- fail_on: high
370
- ```
371
-
372
- ```bash
373
- npm-scan scan target --policy .npm-scan.yml
374
- ```
375
-
376
- ### Environment variables
377
-
378
- | Variable | Description | Default |
379
- |----------|-------------|---------|
380
- | `NPM_SCAN_LICENSE_KEY` | Premium / enterprise license key | β€” |
381
- | `NPM_SCAN_DATA_DIR` | Scan history directory | `./.npm-scan` |
382
- | `NPM_SCAN_LOG_LEVEL` | Log verbosity | `info` |
383
- | `NPM_SCAN_LICENSE_SECRET` | HMAC key for license generation/validation | `npm-scan-default-dev-key` |
384
-
385
- ### IOC configuration
386
-
387
- Campaign detectors use seed IOC files for known-malicious fingerprints:
388
-
389
- | IOC File | Detector | Types |
390
- |----------|----------|-------|
391
- | `backend/detectors/mini-shai-hulud/iocs.json` | Mini Shai-Hulud (Waves 1–3) | `packageScope`, `publisherAccount`, `sha512`, `extensionId` |
392
- | `backend/detectors/trapdoor/iocs.json` | TrapDoor | `publisherAccount`, `campaignMarker`, `payloadFilename`, `payloadSize`, `xorKey`, `c2Domain`, `gistDomain` |
393
- | `backend/detectors/node-ipc-compromise/iocs.json` | node-ipc compromise | `publisherAccount`, `c2Domain`, `c2IP`, `exfilZone`, `payloadHash` |
394
- | `backend/vsix-scan/vsix-iocs.json` | VSIX extension scan | `extensionId`, `publisherAccount`, `orphanCommitHash` |
395
-
396
- 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.
397
-
398
- ### Premium licensing
399
-
400
- Contact leo@lateos.ai for a premium/enterprise license key.
401
-
402
- ```bash
403
- # Use it
404
- npm-scan scan target --license-key <key>
405
- npm-scan report --pdf --license-key <key>
406
- npm-scan report --siem cef --license-key <key>
407
- ```
408
-
409
- ---
410
-
411
- ## πŸ”— Integrations
412
-
413
- ### GitHub Actions CI (for this repo)
414
-
415
- Every push and PR runs tests across Node 18, 20, and 22:
416
-
417
- ```yaml
418
- # .github/workflows/ci.yml
419
- name: CI
420
- on:
421
- push:
422
- branches: [ main ]
423
- pull_request:
424
- branches: [ main ]
425
- jobs:
426
- test:
427
- runs-on: ubuntu-latest
428
- strategy:
429
- matrix:
430
- node-version: [18, 20, 22]
431
- steps:
432
- - uses: actions/checkout@v4
433
- - uses: actions/setup-node@v4
434
- with:
435
- node-version: ${{ matrix.node-version }}
436
- cache: 'npm'
437
- - run: npm ci
438
- - run: npm test
439
- - run: npm run test:coverage
440
- - run: node --test test/detectors-corpus.test.js
441
- - run: npm run lint
442
- - run: npm run build
443
- ```
444
-
445
- ### GitHub Action (for downstream users)
446
-
447
- Scan your project's `package-lock.json` on every PR β€” detects typosquats, obfuscated payloads, credential harvesters, and worm propagation before they reach production. **SARIF output shows findings directly in GitHub's Security tab (Code Scanning).**
448
-
449
- ```yaml
450
- # .github/workflows/scan.yml
451
- name: npm-scan
452
- on:
453
- pull_request:
454
- paths:
455
- - 'package-lock.json'
456
- - '**/package.json'
457
- jobs:
458
- scan:
459
- runs-on: ubuntu-latest
460
- steps:
461
- - uses: actions/checkout@v4
462
- - uses: lateos/npm-scan@v1
463
- with:
464
- scan-type: lockfile
465
- sarif: results.sarif
466
- fail-on: high
467
- - name: Upload SARIF to Security tab
468
- uses: github/codeql-action/upload-sarif@v3
469
- with:
470
- sarif_file: results.sarif
471
- ```
472
-
473
- #### Action inputs
474
-
475
- | Input | Default | Description |
476
- |-------|---------|-------------|
477
- | `scan-type` | `lockfile` | `lockfile` to scan `package-lock.json` or `package` to scan a specific npm package |
478
- | `package` | β€” | Package name (required when `scan-type=package`) |
479
- | `fail-on` | `high` | Fail the workflow at this severity threshold: `none`, `low`, `medium`, `high`, `critical` |
480
- | `policy-file` | β€” | Path to a YAML/JSON policy file for allowlists, severity overrides, and suppressions |
481
- | `license-key` | β€” | Premium license key for SIEM export and PDF reports |
482
- | `siem-format` | β€” | SIEM output: `cef`, `ecs`, `sentinel`, `qradar` (premium) |
483
- | `sbom-format` | β€” | SBOM output: `json`, `xml`, `spdx` |
484
-
485
- #### Action outputs
486
-
487
- | Output | Description |
488
- |--------|-------------|
489
- | `findings-count` | Number of findings detected |
490
- | `scan-id` | Scan ID for later reference in reports |
491
-
492
- #### Example: scan a specific package with policy + SBOM
493
-
494
- ```yaml
495
- - uses: lateos/npm-scan@v1
496
- with:
497
- scan-type: package
498
- package: lodash
499
- policy-file: .npm-scan.yml
500
- sbom-format: spdx
501
- fail-on: critical
502
- ```
503
-
504
- #### Example: scan with SIEM export (premium)
505
-
506
- ```yaml
507
- - uses: lateos/npm-scan@v1
508
- with:
509
- scan-type: lockfile
510
- siem-format: cef
511
- license-key: ${{ secrets.NPM_SCAN_LICENSE_KEY }}
512
- ```
513
-
514
- ### CI/CD pipeline
515
-
516
- Integrate directly into your existing pipeline without the composite action:
517
-
518
- ```bash
519
- # Scan lockfile, fail build on high severity
520
- npm-scan scan-lockfile --policy .npm-scan.yml || exit 1
521
-
522
- # Scan a specific package, fail on critical only
523
- npm-scan scan lodash --policy .npm-scan.yml || exit 1
524
-
525
- # Generate SBOM as a build artifact
526
- npm-scan scan express --sbom spdx > express-sbom.spdx.json
527
-
528
- # Generate HTML compliance report in CI
529
- npm-scan report --html > report.html
530
-
531
- # Upload report as an artifact
532
- # uses: actions/upload-artifact@v4
533
- # with:
534
- # name: npm-scan-report
535
- # path: report.html
536
- ```
537
-
538
- ### Docker
539
-
540
- See the [Docker quick-start section](#-run-lateosnpm-scan-anywhere-with-docker--zero-installation) above for pull commands, Compose pipeline, and multi-arch images.
541
-
542
- Scan your project's `package-lock.json` on every PR β€” detects typosquats, obfuscated payloads, credential harvesters, and worm propagation before they reach production:
543
-
544
- ```yaml
545
- # .github/workflows/scan.yml
546
- name: npm-scan
547
- on:
548
- pull_request:
549
- paths:
550
- - 'package-lock.json'
551
- - '**/package.json'
552
- jobs:
553
- scan:
554
- runs-on: ubuntu-latest
555
- steps:
556
- - uses: actions/checkout@v4
557
- - uses: actions/setup-node@v4
558
- with:
559
- node-version: 20
560
- - name: Scan lockfile
561
- uses: lateos/npm-scan@v1
562
- with:
563
- scan-type: lockfile
564
- fail-on: high
565
- ```
566
-
567
- #### Action inputs
568
-
569
- | Input | Default | Description |
570
- |-------|---------|-------------|
571
- | `scan-type` | `lockfile` | `lockfile` to scan `package-lock.json` or `package` to scan a specific npm package |
572
- | `package` | β€” | Package name (required when `scan-type=package`) |
573
- | `fail-on` | `high` | Fail the workflow at this severity threshold: `none`, `low`, `medium`, `high`, `critical` |
574
- | `policy-file` | β€” | Path to a YAML/JSON policy file for allowlists, severity overrides, and suppressions |
575
- | `license-key` | β€” | Premium license key for SIEM export and PDF reports |
576
- | `siem-format` | β€” | SIEM output: `cef`, `ecs`, `sentinel`, `qradar` (premium) |
577
- | `sbom-format` | β€” | SBOM output: `json`, `xml`, `spdx` |
578
-
579
- #### Action outputs
580
-
581
- | Output | Description |
582
- |--------|-------------|
583
- | `findings-count` | Number of findings detected |
584
- | `scan-id` | Scan ID for later reference in reports |
585
-
586
- #### Example: scan a specific package with policy + SBOM
587
-
588
- ```yaml
589
- - uses: lateos/npm-scan@v1
590
- with:
591
- scan-type: package
592
- package: lodash
593
- policy-file: .npm-scan.yml
594
- sbom-format: spdx
595
- fail-on: critical
596
- ```
597
-
598
- #### Example: scan with SIEM export (premium)
599
-
600
- ```yaml
601
- - uses: lateos/npm-scan@v1
602
- with:
603
- scan-type: lockfile
604
- siem-format: cef
605
- license-key: ${{ secrets.NPM_SCAN_LICENSE_KEY }}
606
- ```
607
-
608
- ### CI/CD pipeline
609
-
610
- Integrate directly into your existing pipeline without the composite action:
611
-
612
- ```bash
613
- # Scan lockfile, fail build on high severity
614
- npm-scan scan-lockfile --policy .npm-scan.yml || exit 1
615
-
616
- # Scan a specific package, fail on critical only
617
- npm-scan scan lodash --policy .npm-scan.yml || exit 1
618
-
619
- # Generate SBOM as a build artifact
620
- npm-scan scan express --sbom spdx > express-sbom.spdx.json
621
-
622
- # Generate HTML compliance report in CI
623
- npm-scan report --html > report.html
624
-
625
- # Upload report as an artifact
626
- # uses: actions/upload-artifact@v4
627
- # with:
628
- # name: npm-scan-report
629
- # path: report.html
630
- ```
631
-
632
- ### Pre-commit hook
633
-
634
- Block supply chain threats **before** they reach version control β€” no CI required.
635
-
636
- ```bash
637
- # One-liner install (requires Node 18+, Git)
638
- npx husky@latest init && npm install && npx husky add .husky/pre-commit "npx lint-staged"
639
- ```
640
-
641
- **What it does:** On every `git commit`, lint-staged detects staged changes to `package.json` or `package-lock.json` and runs `npm-scan scan-lockfile --fail-on high`. Commits are blocked if threats are found.
642
-
643
- ```bash
644
- $ git commit -m "bump lodash"
645
- βœ” Preparing lint-staged configuration...
646
- βœ” Running tasks for staged package*.json files...
647
- βœ” npm-scan scan-lockfile --fail-on high
648
- πŸ”΄ ATK-003: Credential exfiltration (DNS lookup to credentialharvest.example.com)
649
- πŸ”΄ ATK-007: Typosquat detected (lodash@7.7.7)
650
- ⚠ Exiting with code 1 β€” threat(s) found
651
-
652
- npm scan β€’ @lateos/npm-scan v0.11.6
653
- error: Command failed with exit code 1.
654
- ```
655
-
656
- Add `--no-verify` to bypass for emergencies (`git commit -m "emergency fix" --no-verify`).
657
-
658
- ### Docker
659
-
660
- See the [Docker quick-start section](#-run-lateosnpm-scan-anywhere-with-docker--zero-installation) above for pull commands, Compose pipeline, and multi-arch images.
661
-
662
- ---
663
-
664
- ## πŸ—ΊοΈ Roadmap & Enterprise Features
665
-
666
- ### Free tier (shipped)
667
-
668
- - 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) + **TRAPDOOR** cross-ecosystem attack detection (9 rules) + **NODE_IPC_COMPROMISE** expired-domain hijack detection (11 rules)
669
- - SBOM output (CycloneDX + SPDX)
670
- - HTML, text, and compliance reports (NIST + EU CRA)
671
- - Policy-as-code engine (YAML)
672
- - Local SQLite scan history
673
- - GitHub Action
674
- - Pre-commit hook (husky + lint-staged)
675
- - Docker images + Compose pipeline
676
- - Watch mode (--watch / --monorepo for auto-rescan)
677
- - VS Code extension scanning (--vsix flag with Marketplace + Open VSX registries)
678
-
679
- ### Premium (πŸ” license key)
680
-
681
- - PDF compliance reports with NIST traceability matrix
682
- - SIEM export (Splunk CEF, Elastic ECS, Microsoft Sentinel, IBM QRadar)
683
- - Dynamic sandbox (gVisor-based β€” ATK-008–010)
684
- - Reachability analysis (call graph filtering)
685
-
686
- ### Enterprise (🏒 custom license)
687
-
688
- - SAML 2.0 SSO (Okta, Azure AD, OneLogin, Keycloak)
689
- - REST API + webhooks (FastAPI)
690
- - Team RBAC + audit logs
691
- - Helm chart for Kubernetes deployment
692
- - PostgreSQL backend for hosted/team tier
693
- - SLA-backed priority support
694
-
695
- ---
696
-
697
- ## 🀝 Contributing
698
-
699
- We welcome contributions β€” especially new detectors, improved evasion resistance, and compliance templates.
700
-
701
- See [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md) for the ATK governance process. Every new detector requires:
702
-
703
- 1. A proof-of-concept sample
704
- 2. A detection rule with tests
705
- 3. False-positive analysis on top-500 npm packages
706
- 4. NIST 800-161 control mapping
707
-
708
- ### Testing
709
-
710
- The project uses the **Node.js native test runner** (`node:test` + `assert/strict`).
711
-
712
- ```bash
713
- # Run all tests
714
- npm test
715
-
716
- # Run tests with coverage
717
- npm run test:coverage
718
-
719
- # Run tests with verbose spec output
720
- npm run test:verbose
721
-
722
- # Run local malicious/clean corpus (no network needed)
723
- node --test test/detectors-corpus.test.js
724
- ```
725
-
726
- **Test structure:**
727
- - `test/fixtures/mock-data.js` β€” shared mock scans, packages, and code snippets
728
- - `test/megalodon.test.js` β€” 30 Megalodon campaign detection tests (D1–D4 + aggregator + runAll integration)
729
- - `test/db.test.js` β€” database CRUD (save, query, persist)
730
- - `test/detectors-edge-cases.test.js` β€” per-detector boundary tests (no-ops, clean clears, severity)
731
- - `test/detectors-corpus.test.js` β€” 33 malicious + 50 clean tarball integration (offline)
732
- - `test/fetch.test.js` β€” tarball extraction, temp directory cleanup
733
- - `test/policy-edge-cases.test.js` β€” edge cases in suppress, override, load validation
734
- - `test/policy.test.js` β€” policy YAML/JSON load, apply, suppress, severity override tests
735
- - `test/report-snapshots.test.js` β€” HTML/text/CRA/PDF format assertions
736
- - `test/report.test.js` β€” SARIF, CSV, STIG, risk score format tests
737
- - `test/lockfile.test.js` β€” npm/yarn/pnpm parser, auto-detect, ATK-007/011 lockfile tests
738
- - `test/hf-impersonation.test.js` β€” 13 HF impersonation detection tests (no-ref, exact match, spoof, README clone, artifact mismatch, postinstall escalation, new-org tag)
739
- - `test/mini-shai-hulud.test.js` β€” 22 Mini Shai-Hulud worm campaign detection tests (burst, sibling, SLSA, maintainer, IOC, exfil, wave attribution)
740
- - `test/vsix-scan/burst-publish.test.js` β€” 4 VSIX burst publish tests (threshold, sub-threshold, hot-pull, Open VSX window)
741
- - `test/vsix-scan/publisher-anomaly.test.js` β€” 5 publisher anomaly tests (cross-namespace, new-account, add+publish, substitution, silent)
742
- - `test/vsix-scan/activation-event-risk.test.js` β€” 5 activation event risk tests (onStartupFinished, wildcard, escalation, first-time, silent)
743
- - `test/vsix-scan/orphan-commit-fetch.test.js` β€” 5 orphan commit tests (GitHub SHA, npx git, MCP exfil, Bun install, silent)
744
- - `test/vsix-scan/known-ioc.test.js` β€” 4 known IOC tests (extensionId, publisher window, outside window)
745
- - `test/vsix-scan/exfil-pattern.test.js` β€” 5 exfil pattern tests (creds, DNS tunnel, AES+RSA, anti-analysis, silent)
746
- - `test/vsix-scan/integration.test.js` β€” 4 integration tests (Nx Console CRITICAL, safe version clean, orphan commit, skipNetwork)
747
- - `test/cve-2026-48710-badhost/manifest.test.js` β€” 13 Python manifest parsing tests (requirements.txt, pyproject.toml, poetry.lock, version edge cases)
748
- - `test/cve-2026-48710-badhost/transitive.test.js` β€” 7 transitive dependency tests (Tier 1/2, fastapi version gating, pin suppression)
749
- - `test/cve-2026-48710-badhost/codePattern.test.js` β€” 6 static code pattern tests (auth context, INFO fallthrough, scope suppression)
750
- - `test/cve-2026-48710-badhost/integration.test.js` β€” 4 integration tests (end-to-end composite findings, clean project, no Python files)
751
- - `test/trapdoor.test.js` β€” 40 TrapDoor campaign detection tests (D1–D9: campaign marker, payload fingerprint, publisher blocklist, Gist exfil, AI poisoning, lure name, crypto primitives, XOR key, credential validation)
752
- - `test/node-ipc.test.js` β€” 37 node-ipc compromise detection tests (D1–D11: version blocklist, tarball hash, CJS injection, payload hash, DNS C2 pattern, bootstrap resolver, DNS TXT exfil, runtime trigger, temp artifact, unauthorized publisher, blast radius)
753
- - `test/cli.test.js` β€” commander integration tests (help, version, scan, report, error handling)
754
- - `test/cli-lockfile.test.js` β€” scan-lockfile CLI options, yarn/pnpm/monorepo/watch tests
755
-
756
- ### Need help?
757
-
758
- - πŸ”’ See [security policy](SECURITY.md) for vulnerability disclosure
759
- - πŸ“– Read the [project plan](docs/project-plan.md)
760
- - 🧬 Review the [attack taxonomy](docs/attack-taxonomy.md)
761
- - πŸ› Open an issue or PR
762
-
763
- ---
764
-
765
- ## πŸ“„ License
766
-
767
- Apache-2.0 core + Commons Clause.
768
- See [`LICENSING.md`](LICENSING.md) for the exact boundary between free and premium features.
769
-
770
- ---
771
-
772
- ## πŸ‘€ About the Maintainer
773
-
774
- **Roongrunchai Chongolnee** β€” creator and maintainer of `@lateos/npm-scan`. Certified security professional (CISSP, CEH, Cisco Security, AWS Cloud Practitioner) with a decade of infrastructure and application security experience at Philips. I built this tool to give the open-source community a practical, detector-driven defense against supply-chain malware β€” and I'm committed to keeping it transparent, community-owned, and continuously improved.
775
-
776
- [![LinkedIn](https://img.shields.io/badge/LinkedIn-0A66C2?style=flat-square&logo=linkedin)](https://www.linkedin.com/in/roongrunchai-chong-c-ab9742108/)
777
- [![GitHub](https://img.shields.io/badge/GitHub-lateos--ai-181717?style=flat-square&logo=github)](https://github.com/lateos-ai/npm-scan)
778
-
779
- Issues, ideas, and pull requests are always welcome β€” security is strongest when we collaborate.
780
-
781
- ---
782
-
783
- ```
784
- @lateos/npm-scan β€” npm supply chain security scanner
785
- Copyright (C) 2026 Lateos
786
-
787
- Licensed under the Apache License, Version 2.0 (the "License");
788
- you may not use this file except in compliance with the License.
789
-
790
- Unless required by applicable law or agreed to in writing, software
791
- distributed under the License is distributed on an "AS IS" BASIS,
792
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
793
- ```
794
-
795
- ---
796
-
797
- **Scan your first package now:**
798
-
799
- ```bash
800
- npx @lateos/npm-scan scan lodash
801
- ```
1
+ # @lateos/npm-scan
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@lateos/npm-scan?style=flat-square)](https://www.npmjs.com/package/@lateos/npm-scan)
4
+ [![License](https://img.shields.io/badge/license-Apache%202.0%20%2B%20Commons%20Clause-blue?style=flat-square)](LICENSING.md)
5
+ [![Node](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](package.json)
6
+ [![Tests](https://img.shields.io/badge/tests-536%20passing-brightgreen?style=flat-square)](https://github.com/lateos-ai/npm-scan)
7
+ [![Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen?style=flat-square)](https://github.com/lateos-ai/npm-scan)
8
+ [![Docker](https://img.shields.io/badge/docker-lateos%2Fnpm--scan-2496ED?style=flat-square&logo=docker)](https://hub.docker.com/r/lateos/npm-scan)
9
+ [![Sigstore](https://img.shields.io/static/v1?label=Sigstore&message=Provenance&color=green&style=flat-square&logo=sigstore)](https://github.com/lateos-ai/npm-scan/actions/workflows/publish.yml)
10
+
11
+ [![δΈ­ζ–‡](https://img.shields.io/badge/lang-zh--CN-red?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.zh.md)
12
+ [![ζ—₯本θͺž](https://img.shields.io/badge/lang-ja-purple?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.ja.md)
13
+ [![FranΓ§ais](https://img.shields.io/badge/lang-fr-orange?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.fr.md)
14
+ [![Deutsch](https://img.shields.io/badge/lang-de-green?style=flat-square)](https://github.com/lateos-ai/npm-scan/blob/main/README.de.md)
15
+
16
+ **Modern supply chain security for the npm ecosystem.**
17
+ Static + behavioral analysis that catches what npm audit, Snyk, and Socket miss β€” obfuscated payloads, credential stealers, conditional triggers, sandbox evasion, and worm-like propagation.
18
+
19
+ ---
20
+
21
+ ## πŸ“Œ The Problem
22
+
23
+ The 2025–2026 wave of npm supply chain attacks proved that traditional tooling is no longer enough.
24
+
25
+ Attackers have moved past simple typosquatting. They now ship **obfuscated preinstall hooks**, **credential harvesters hidden behind environment detection**, **dormant backdoors with time-based activation**, and **worm-style transitive propagation** that spreads through peer dependencies.
26
+
27
+ A growing attack vector is **HuggingFace org impersonation** β€” packages that masquerade as legitimate HF model repositories (e.g., `0penai/gpt2` instead of `openai/gpt2`) to trick users into downloading malicious model artifacts during CI/CD pipelines, often bundled with suspicious binaries (`.exe`, `.dll`) in model repos that deep-learned tools trust by default.
28
+
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
+
31
+ The **Mini Shai-Hulud worm campaign** (May 2026) hit the npm ecosystem in three waves β€” TanStack CI/CD hijack (84 artifacts in 6 minutes), AntV/atool maintainer compromise (600+ malicious versions across 300+ packages), and Nx Console VS Code extension poisoning (CVE-2026-48027) β€” all using ctf-scramble-v2 obfuscation, daemonized persistence with CI environment checks, geographic killswitches targeting sanctioned regions, and GitHub C2 dead-drop channels for token recovery. **@lateos/npm-scan** now detects all 10 Mini Shai-Hulud signals across two detector suites.
32
+
33
+ The **TrapDoor campaign** (May 2026) spans npm, PyPI, and Crates.io β€” 34 malicious packages, 384+ versions attributed to a single publisher, targeting crypto, DeFi, Solana, and AI developers with Fernet + ECDH encrypted payloads, AI context poisoning via zero-width Unicode injection in `.cursorrules`/`CLAUDE.md`, and credential live-validation against AWS STS and GitHub API before exfiltration. **@lateos/npm-scan** now detects all 9 TrapDoor signals.
34
+
35
+ The **node-ipc compromise** (May 14, 2026) weaponized an expired maintainer email domain to hijack one of npm's most depended-upon packages (822K weekly downloads). Three malicious versions (9.1.6, 9.2.3, 12.0.1) delivered an 80KB credential stealer via DNS TXT tunneling β€” no HTTP, no postinstall hook, invisible to HTTP-layer firewalls. **@lateos/npm-scan** now detects all 11 node-ipc compromise signals.
36
+
37
+ The **Mass Typosquatting campaign (vpmdhaj)** (May 2026) weaponized the `vpmdhaj` npm maintainer account to publish 14 typosquatted packages in a 4-hour window β€” targeting AWS/CI/CD environments with preinstall stagers (`setup.mjs`, `stager.js`), Bun runtime abuse, and cloud credential exfiltration (AWS IMDSv2, ECS task roles, Vault, GitHub tokens). **@lateos/npm-scan** now detects all 3 typosquatting campaign signals.
38
+
39
+ The **Axios Registry Poisoning campaign** (May 2026) compromised the npm registry's axios package metadata to publish `axios@1.14.1` and `axios@0.30.4` with injected dependencies (`plain-crypto-js`) containing cross-platform RAT payloads with C2 callbacks, process injection, and system persistence. **@lateos/npm-scan** now detects all 3 axios poisoning signals.
40
+
41
+ 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.
42
+
43
+ **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.
44
+
45
+ **@lateos/npm-scan** was built for this moment.
46
+
47
+ ---
48
+
49
+ ## πŸ”¬ Why @lateos/npm-scan?
50
+
51
+ | Capability | npm audit | Snyk | Socket | **@lateos/npm-scan** |
52
+ |---|---|---|---|---|
53
+ | Known CVE matching | βœ… | βœ… | ❌ | βœ… |
54
+ | Static analysis | ❌ | βœ… | βœ… | βœ… |
55
+ | Obfuscated payload detection | ❌ | ❌ | ❌ | βœ… |
56
+ | AST-level heuristic analysis | ❌ | ❌ | ❌ | βœ… |
57
+ | Runtime behavioral sandbox | ❌ | ❌ | βœ… | βœ… |
58
+ | Conditional trigger detection (ATK-009) | ❌ | ❌ | ❌ | βœ… |
59
+ | Sandbox evasion detection (ATK-010) | ❌ | ❌ | ❌ | βœ… |
60
+ | Transitive worm propagation (ATK-011) | ❌ | ❌ | ❌ | βœ… |
61
+ | Campaign detection (Megalodon CI/CD) | ❌ | ❌ | ❌ | βœ… |
62
+ | Worm campaign detection (Mini Shai-Hulud Wave 1–3) | ❌ | ❌ | ❌ | βœ… |
63
+ | HF model repo impersonation + README clone | ❌ | ❌ | ❌ | βœ… |
64
+ | VS Code extension supply chain scan (--vsix) | ❌ | ❌ | ❌ | βœ… |
65
+ | Python vulnerability detection (CVE-2026-48710 BadHost) | ❌ | ❌ | ❌ | βœ… |
66
+ | Cross-ecosystem attack detection (TrapDoor) | ❌ | ❌ | ❌ | βœ… |
67
+ | Expired-domain hijack detection (node-ipc) | ❌ | ❌ | ❌ | βœ… |
68
+ | Malware obfuscation detection (ctf-scramble-v2) | ❌ | ❌ | ❌ | βœ… |
69
+ | Mass typosquatting campaign (vpmdhaj maintainer) | ❌ | ❌ | ❌ | βœ… |
70
+ | Registry poisoning detection (axios fake versions) | ❌ | ❌ | ❌ | βœ… |
71
+ | Attack taxonomy (ATK series) | ❌ | ❌ | ❌ | βœ… |
72
+ | SBOM output (CycloneDX + SPDX) | ❌ | βœ… | ❌ | βœ… |
73
+ | SARIF v2.1 (GitHub Code Scanning) | ❌ | ❌ | ❌ | βœ… |
74
+ | NIST 800-161 compliance reporting | ❌ | ❌ | ❌ | βœ… |
75
+ | EU CRA compliance reporting | ❌ | ❌ | ❌ | βœ… |
76
+ | SIEM export (CEF / ECS / Sentinel / QRadar) | ❌ | ❌ | ❌ | βœ… |
77
+ | Runs entirely locally β€” no telemetry | βœ… | ❌ | ❌ | βœ… |
78
+ | Policy-as-code (YAML allowlists) | ❌ | ❌ | ❌ | βœ… |
79
+
80
+ > **Privacy first.** All scanning happens on your machine. No code leaves your environment. No telemetry. No cloud dependency.
81
+
82
+ ---
83
+
84
+ ## ✨ Key Features
85
+
86
+ | Icon | Feature | Description |
87
+ |------|---------|-------------|
88
+ | πŸ•΅οΈ | **Heuristic static analysis** | AST-level inspection catches obfuscation, eval chains, env probing, and suspicious lifecycle scripts that regex-based tools miss |
89
+ | 🧠 | **Behavioral detection** | Identifies conditional triggers (time-based, CI-aware), sandbox evasion, and dormant activation patterns |
90
+ | 🧬 | **ATK attack taxonomy** | 11 classified attack types with NIST 800-161 mappings β€” versioned, documented, and PR-able |
91
+ | πŸͺ± | **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) |
92
+ | 🧩 | **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) |
93
+ | 🐍 | **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 |
94
+ | πŸͺ€ | **Cross-ecosystem attack detection** | TrapDoor β€” 9 sub-checks: campaign marker P-2024-001, trap-core.js payload fingerprint, publisher blocklist asdxzxc, Gist-based credential exfil, AI config zero-width Unicode poisoning, crypto/DeFi lure name heuristic, Fernet+ECDH encryption, XOR key cargo-build-helper-2026, STS/GitHub API credential validation |
95
+ | πŸ“‘ | **Expired-domain hijack detection** | node-ipc compromise β€” version blocklist (9.1.6/9.2.3/12.0.1), tarball SHA-256 verification, CJS vs ESM size anomaly with IIFE injection, DNS-over-non-standard-port C2, bootstrap resolver sh.azurestaticprovider.net, DNS TXT exfil zone bt.node.js, setImmediate() runtime trigger, ~/nt-*/ staging artifacts, unauthorized publisher atiertant, lockfile blast-radius with safe pin recommendations |
96
+ | ☣️ | **Malware obfuscation detection** | ctf-scramble-v2 detection β€” scans package dist/lib for known malware obfuscation patterns (ctf-scramble-v2, ctf-scramble-v3), halts analysis immediately with max severity CRITICAL stop condition |
97
+ | 🎭 | **Mass typosquatting campaign detection** | vpmdhaj maintainer blocklist with stop condition, levenshtein-based typosquat detection (opensearch-setup, env-config-manager), preinstall stager identification (setup.mjs, stager.js, Bun runner), AWS ECS/Vault/GitHub credential exfiltration patterns |
98
+ | ☠️ | **Registry poisoning detection** | Axios version blocklist (1.14.1/0.30.4) with stop condition, decoy dependency discovery (plain-crypto-js), cross-platform RAT payload detection (DLL injection, launchd/systemd/cron persistence, PowerShell IEX, C2 callbacks) |
99
+ | πŸ” | **Provenance audit trail** | Aureus-Elicitor v1.7 framework β€” HMAC-SHA256 signed detection manifests, content-hash verified audit trails, rule provenance URLs, campaign source attribution. Every finding includes cryptographically verifiable provenance metadata |
100
+ | πŸ“¦ | **SBOM generation** | CycloneDX 1.5 and SPDX 2.3 with findings embedded as vulnerabilities |
101
+ | πŸ” | **SARIF output** | GitHub Advanced Security / CodeQL compatible SARIF v2.1 β€” shows findings directly in Security tab |
102
+ | 🧾 | **Compliance reporting** | NIST SP 800-161 traceability matrix + EU Cyber Resilience Act mapping (free tier) |
103
+ | πŸ”Œ | **SIEM export** | Splunk CEF, Elastic ECS, Microsoft Sentinel, IBM QRadar formats (premium) |
104
+ | πŸ“œ | **Policy-as-code** | YAML/JSON policy engine with allowlists, severity overrides, suppressions, and fail-on thresholds |
105
+ | 🐳 | **Docker + GitHub Action** | Multi-arch images, one-command Compose pipeline, PR scan action |
106
+ | πŸ›‘οΈ | **Zero telemetry** | No data leaves your machine. No cloud. No callbacks. |
107
+ | πŸ’Ύ | **Local scan history** | SQLite-backed persistence, zero external dependencies |
108
+ | πŸͺ | **Pre-commit hook** | Block threats before commit β€” one-liner install, scans `package-lock.json` changes |
109
+ | πŸ€– | **HF impersonation detection** | Detects typosquatted HuggingFace orgs (Jaro-Winkler), README clones (SimHash), artifact mismatches (`.exe` in model repos), and new-org amplifier β€” with lazy two-stage evaluation, zero network in Stage 1 |
110
+ | πŸ“Ž | **Yarn + pnpm support** | `scan-lockfile` parses `yarn.lock` and `pnpm-lock.yaml` alongside `package-lock.json` |
111
+
112
+ ---
113
+
114
+ ## ⚑ Quick Start
115
+
116
+ ```bash
117
+ # Install globally
118
+ npm install -g @lateos/npm-scan
119
+
120
+ # Scan a single package
121
+ npm-scan scan lodash
122
+
123
+ # Scan your lockfile
124
+ npm-scan scan-lockfile
125
+
126
+ # View latest scans
127
+ npm-scan report
128
+ ```
129
+
130
+ **No install? No problem:**
131
+
132
+ ```bash
133
+ npx @lateos/npm-scan scan commander
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 🐳 Run @lateos/npm-scan anywhere with Docker β€” zero installation
139
+
140
+ ```bash
141
+ # Pull and run a single scan β€” no Node.js or npm required
142
+ docker run --rm lateos/npm-scan:cli scan lodash
143
+
144
+ # Full pipeline with persistent storage and Compose
145
+ docker compose --profile pipeline up -d
146
+ ```
147
+
148
+ No Node.js. No `npm install`. No global packages. Works on any system with Docker β€” CI servers, air-gapped environments, Kubernetes clusters. Multi-arch images for `linux/amd64` and `linux/arm64`.
149
+
150
+ ---
151
+
152
+ ## πŸ›‘οΈ Government & SOC 2 Ready
153
+
154
+ | Feature | SOC 2 Controls | NIST 800-161 | STIG/FedRAMP Alignment |
155
+ |---------|-------|--------------|--------------|
156
+ | Audit logs (--audit-log) | CC6.8 | AU-2 | βœ“ |
157
+ | FIPS crypto (--fips) | CC6.1 | SC-13 | βœ“ |
158
+ | STIG report (--stig) | CC7.3 | RA-5 | βœ“ |
159
+ | Offline cache (--cache-dir) | A1.2 | SC-8 | βœ“ |
160
+ | Sigstore provenance | CC6.2 | SI-7 | βœ“ |
161
+ | SBOM (SPDX/CycloneDX) | CC7.4 | SA-10 | βœ“ |
162
+
163
+ ```bash
164
+ # Air-gapped scan with full compliance
165
+ npm-scan scan-lockfile --cache-dir /offline/cache --audit-log /var/log/npm-scan.audit --fips
166
+ npm-scan report --stig
167
+ ```
168
+
169
+ [![SOC 2 Ready](https://img.shields.io/badge/SOC%202-Ready-green?style=flat-square&logo=aicpa)](https://www.aicpa.org/interestareas/frc/assuranceadvisoryservices/sorhome.html#soc2)
170
+ [![FedRAMP Aligned](https://img.shields.io/badge/FedRAMP-Aligned-blue?style=flat-square&logo=fedramp)](https://fedramp.gov/baselines/)
171
+
172
+ ---
173
+
174
+ ## ☁️ BYOC β€” Bring Your Own Cloud
175
+
176
+ Deploy npm-scan in your VPC with full data sovereignty. No data leaves your infrastructure.
177
+
178
+ | Feature | Description |
179
+ |---------|-------------|
180
+ | **Self-hosted** | Run on EKS/GKE/AKS in your AWS/Azure/GCP account |
181
+ | **SIEM Export** | CEF/ECS/Sentinel/QRadar to your existing SIEM |
182
+ | **SSO/OIDC** | SAML/OIDC integration with your identity provider |
183
+ | **PDF Reports** | Generate NIST-compliant PDF reports locally |
184
+ | **External DB** | Connect to your existing PostgreSQL/Redis |
185
+
186
+ ```bash
187
+ # Deploy to your VPC with Helm
188
+ git clone https://github.com/lateos-ai/npm-scan.git
189
+ cd npm-scan/deploy/helm
190
+ helm install npm-scan -f values.byoc.yaml .
191
+
192
+ # BYOC values example (see values.byoc.yaml)
193
+ premium:
194
+ enabled: true
195
+ edition: enterprise
196
+ byoc:
197
+ enabled: true
198
+ cloudProvider: aws
199
+ vpcId: vpc-xxx
200
+ region: us-east-1
201
+ ```
202
+
203
+ **Pricing**: Enterprise license $10k/yr β€” self-supported (docs + GitHub issues).
204
+
205
+ ---
206
+
207
+ ## πŸ“– Usage Examples
208
+
209
+ ### Scan a single package
210
+
211
+ ```bash
212
+ # Default JSON output with all findings
213
+ npm-scan scan axios
214
+
215
+ # Generate an SBOM alongside the scan
216
+ npm-scan scan express --sbom # CycloneDX JSON
217
+ npm-scan scan express --sbom xml # CycloneDX XML
218
+ npm-scan scan express --sbom spdx # SPDX 2.3
219
+
220
+ # Apply a YAML policy
221
+ npm-scan scan some-package --policy .npm-scan.yml
222
+
223
+ # Scan a local tarball (no registry fetch needed)
224
+ npm-scan scan --file path/to/malicious-package.tgz
225
+
226
+ # Scan a VS Code extension for Marketplace supply chain attacks
227
+ npm-scan scan --vsix nrwl.angular-console
228
+
229
+ # Scan a package AND a VSIX extension together (findings merge)
230
+ npm-scan scan lodash --vsix nrwl.angular-console
231
+ ```
232
+
233
+ ### Scan a lockfile
234
+
235
+ ```bash
236
+ # Scan a single package
237
+ npm-scan scan lodash
238
+
239
+ # Scan your lockfile
240
+ npm-scan scan-lockfile
241
+
242
+ # Scan a VS Code extension for supply chain threats
243
+ npm-scan scan --vsix nrwl.angular-console
244
+
245
+ # View latest scans
246
+ npm-scan report
247
+ ```
248
+
249
+ ### Generate reports
250
+
251
+ ```bash
252
+ # List all recent scans
253
+ npm-scan report
254
+
255
+ # View a specific scan
256
+ npm-scan report -i 42
257
+
258
+ # Generate an HTML report (free) with full findings + NIST table
259
+ npm-scan report -i 42 --html
260
+
261
+ # Print NIST 800-161 compliance table
262
+ npm-scan report -i 42 --nist
263
+
264
+ # Print EU CRA compliance table
265
+ npm-scan report --cra
266
+
267
+ # CSV export for Excel / Sheets (audit-ready)
268
+ npm-scan report --csv risks.csv
269
+ npm-scan scan lodash --csv # CSV to stdout
270
+
271
+ # Text report (free)
272
+ npm-scan report --text
273
+
274
+ # PDF report (premium)
275
+ npm-scan report --pdf --license-key <key>
276
+
277
+ # SIEM export (premium)
278
+ npm-scan report --siem cef # Splunk CEF
279
+ npm-scan report --siem ecs # Elastic ECS
280
+ npm-scan report --siem sentinel # Microsoft Sentinel
281
+ npm-scan report --siem qradar # IBM QRadar
282
+
283
+ # Combine all scans into a single report
284
+ npm-scan report --html # all scans
285
+ npm-scan report --pdf # all scans (premium)
286
+ ```
287
+
288
+ ---
289
+
290
+ ## 🧬 Detection Capabilities (ATK Taxonomy)
291
+
292
+ | ID | Attack Class | Detection Method | Severity | NIST 800-161 |
293
+ |---|---|---|---|---|
294
+ | **ATK-001** | Malicious lifecycle scripts (`preinstall`, `postinstall`, `install`) | Static | πŸ”΄ high | SR-3.1 |
295
+ | **ATK-002** | Obfuscated payload delivery (hex, base64, eval chains) | Static | 🟠 medium | SR-4.2 |
296
+ | **ATK-003** | Credential harvesting (env vars, .npmrc, SSH keys) | Static + Dynamic | πŸ”΄ high | SR-5.3 |
297
+ | **ATK-004** | Persistence via editor/config dirs (.vscode, .claude, .cursor) | Static | πŸ”΄ high | SR-6.4 |
298
+ | **ATK-005** | Network exfiltration (GitHub API, DNS tunneling, HTTP C2) | Static + Dynamic | ⚫ critical | SR-7.5 |
299
+ | **ATK-006** | Dependency confusion / namespace squatting | Static (lockfile) | 🟠 medium | SR-2.2 |
300
+ | **ATK-007** | Typosquatting (edit-distance matching) | Static | 🟒 low | SR-2.1 |
301
+ | **ATK-008** | Tarball tampering (published β‰  source) | Static | πŸ”΄ high | SR-8.1 |
302
+ | **ATK-009** | Conditional/dormant triggers (CI detection, time-based) | Behavioral | πŸ”΄ high | SR-9.2 |
303
+ | **ATK-010** | Sandbox evasion / anti-analysis | Behavioral | 🟠 medium | SR-10.3 |
304
+ | **ATK-011** | Transitive propagation (worm-style lateral spread) | Behavioral | πŸ”΄ high | SR-11.4 |
305
+ | **MEGALODON** | Megalodon CI/CD campaign β€” workflow C2 exfil, credential harvest, publish velocity spike, publisher drift | Static + Registry | ⚫ critical | SR-3.1, SR-7.5 |
306
+ | **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 |
307
+ | **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 |
308
+ | **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 |
309
+ | **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 |
310
+ | **TRAPDOOR** | TrapDoor cross-ecosystem attack β€” campaign marker P-2024-001 in files, shared payload trap-core.js filename/48,485-byte fingerprint, publisher blocklist asdxzxc, Gist-based credential exfil (ddjidd564.github.io + credential paths), AI context poisoning via zero-width Unicode in .cursorrules/CLAUDE.md, crypto/DeFi lure name heuristic (<30 days), Fernet+ECDH crypto primitives in postinstall, XOR key cargo-build-helper-2026 in lockfiles, STS/GitHub API credential validation in postinstall | Static + Registry | 🟠 medium / πŸ”΄ high / ⚫ critical | SR-3.1, SR-5.3, SR-7.5 |
311
+ | **NODE_IPC_COMPROMISE** | node-ipc supply chain compromise (May 14, 2026) β€” version blocklist (9.1.6/9.2.3/12.0.1) with safe pins, tarball SHA-256 verification, CJS payload IIFE injection detection (CJS>ESM size differential), injected payload hash match, DNS-over-non-standard-port C2 (setServers + custom resolver), bootstrap resolver sh.azurestaticprovider.net + C2 IP 37.16.75.69, DNS TXT exfiltration zone bt.node.js, setImmediate() runtime trigger, ~/nt-*/ staging artifact detection, unauthorized publisher atiertant, lockfile blast-radius detection with pin recommendations | Static + Registry | ⚫ critical | SR-3.1, SR-5.3, SR-7.5 |
312
+ | **MSH_SUPPLEMENT** | Mini Shai-Hulud supplement β€” ctf-scramble-v2 obfuscation (HALT on match), daemonization persistence (spawn detached, systemd, cron, launchd, Task Scheduler), geographic killswitch detection (ru_RU/be_BY locale checks via process.env.LANG/LC_ALL/Intl.DateTimeFormat), C2 dead-drop indicators (OhNoWhatsGoingOnWithGitHub keyword, GitHub commit scraping + token exfiltration co-occurrence) | Static + Behavioral | ⚫ critical | SR-3.1, SR-7.5, SR-9.2 |
313
+ | **TYPOSQUAT_VPMDHAJ** | Mass Typosquatting campaign (vpmdhaj) β€” maintainer blocklist (HALT on match), vpmdhaj-* namespace prefix detection, levenshtein typosquat matching vs popular packages, preinstall stager identification (setup.mjs/stager.js/bun run with generation tracking), cloud credential exfiltration (AWS IMDSv2, ECS task role tokens, Vault credentials, GITHUB_TOKEN/GH_TOKEN with HTTP exfil) | Static + Registry | ⚫ critical | SR-2.1, SR-3.1, SR-5.3 |
314
+ | **AXIOS_POISONING** | Axios Registry Poisoning β€” version blocklist (1.14.1/0.30.4, HALT on match), decoy dependency injection (plain-crypto-js), crypto-dependency heuristic in non-crypto packages, cross-platform RAT payload detection (PowerShell IEX, launchd, systemd, cron, DLL/LoadLibrary, CreateRemoteThread, binary drops to temp dirs, C2 callbacks) | Static + Behavioral | ⚫ critical | SR-3.1, SR-5.3, SR-7.5 |
315
+
316
+ > **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.
317
+ > **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.
318
+ > **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.
319
+ > **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`.
320
+ > **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.
321
+ > **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.
322
+ > **TRAPDOOR** campaign detection runs 9 sub-detectors across all package files (README.md, package.json, .md, shell scripts, .cursorrules, CLAUDE.md) for the hardcoded marker P-2024-001, scans for trap-core.js by filename or exact 48,485-byte size, unconditionally blocks publisher asdxzxc, detects outbound references to ddjidd564.github.io or gist.github.com combined with credential-path patterns, scans .cursorrules and CLAUDE.md for zero-width Unicode characters (U+200B, U+200C, U+200D, U+FEFF), flags crypto/DeFi-themed packages <30 days old with no prior version history, detects simultaneous Fernet and ECDH/createECDH usage in postinstall JS, and identifies sts.amazonaws.com and api.github.com/user calls in postinstall hooks.
323
+ > **NODE_IPC_COMPROMISE** detection intercepts the expired-domain takeover attack across 11 dimensions: version blocklist with safe-pin recommendations (9.1.5 for 9.x, 12.0.0 for 12.x), tarball SHA-256 hash verification against known malicious hashes, CJS vs ESM size comparison with IIFE suffix pattern detection for injected payload identification, DNS resolver pattern analysis (dns.promises.Resolver + setServers with non-public IP + resolveTxt), bootstrap domain and C2 IP detection, resolveTxt() with bt.node.js zone references, setImmediate() runtime trigger detection, ~/nt-*/ staging artifact path identification, publisher account verification against unauthorized account atiertant, and lockfile scanning for compromised version resolution with safe-pin suggestions.
324
+ > **MSH_SUPPLEMENT** detection augments the existing Mini Shai-Hulud worm campaign with 4 additional sub-detectors: D1 scans all extracted JS files for `require('ctf-scramble-v2')` or `import 'ctf-scramble-v2'` patterns (including variant ctf-scramble-v3+) and returns a CRITICAL stop condition that halts all further scanning. D2 scans lifecycle scripts (preinstall/install/postinstall) for daemonization APIs (`daemon()`, `fork()`, `spawn({detached: true})`), persistence mechanisms (systemd unit files, crontab, launchd plists, Windows Task Scheduler), and CI environment guards (`!process.env.CI`, `process.env.CI === undefined`). D3 scans code for geographic locale checks targeting sanctioned regions (`ru_RU`, `be_BY`) via `process.env.LANG`, `process.env.LC_ALL`, and `Intl.DateTimeFormat().resolvedOptions().timeZone` with `process.exit(0)` silent termination. D4 detects C2 dead-drop indicators including the hardcoded `OhNoWhatsGoingOnWithGitHub` keyword and co-occurring GitHub token access + GitHub API commit scraping patterns. All sub-detectors produce provenance-attached findings with HMAC-SHA256 signed audit trails.
325
+ > **TYPOSQUAT_VPMDHAJ** campaign detection uses 3 sub-detectors: D1 checks the npm registry metadata for the blocked maintainer `vpmdhaj` (CRITICAL stop condition), scans package names for the `vpmdhaj-*` prefix namespace, and runs levenshtein edit-distance matching against a blocklist of popular packages to detect typosquats (e.g., `env-config-manager` mimicking dotenv, `opensearch-setup` mimicking OpenSearch). D2 scans `package.json` for suspicious `preinstall` lifecycle hooks (unusual β€” most packages use postinstall), detects `setup.mjs`, `loader.js`, and `stager.js` entry points, and identifies Bun runtime abuse (`bun run stager.js`) as a stealthy loader technique. D3 scans all extracted files for cloud credential exfiltration patterns targeting AWS IMDSv2 (`169.254.169.254`), ECS task role tokens (`AWS_CONTAINER_AUTHORIZATION_TOKEN`, `AWS_CONTAINER_CREDENTIALS_FULL_URI`), HashiCorp Vault (`VAULT_ADDR`, `VAULT_TOKEN`), and GitHub Actions tokens (`GITHUB_TOKEN`, `GH_TOKEN`) combined with HTTP POST exfiltration or base64 obfuscation to attacker-controlled domains. All findings include provenance metadata with HMAC-SHA256 signed manifests.
326
+ > **AXIOS_POISONING** campaign detection uses 3 sub-detectors: D1 checks the package name and version against a hardcoded blocklist of known-malicious axios versions (`1.14.1`, `0.30.4`) with a CRITICAL stop condition that halts all scanning on match. D2 scans axios `package.json` dependencies for injected decoy packages (`plain-crypto-js`), and applies a heuristic that flags crypto-related dependency additions in non-crypto packages as potentially malicious pre-staged decoys. D3 scans all files and lifecycle scripts for cross-platform RAT indicators: Windows (PowerShell `IEX`, `Invoke-Expression`, `cmd.exe`, binary `.exe` drops to temp dirs), macOS (launchd plist installation via `launchctl load/start`), Linux (systemd unit files, crontab persistence), process injection APIs (`CreateRemoteThread`, `VirtualAllocEx`, `LoadLibrary`/`dlopen`), and C2 network callbacks via HTTP/HTTPS/WebSocket to attacker-controlled servers. Only suspicious code patterns (curl, wget, fetch, exec, spawn, eval, etc.) in lifecycle hooks trigger D3 β€” legitimate build scripts are not flagged.
327
+ > See [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md) for full evasion surface documentation and PoC examples.
328
+
329
+ ---
330
+
331
+ ## πŸ“Š Output & Reports
332
+
333
+ ### Formats
334
+
335
+ | Format | Availability | Description |
336
+ |--------|-------------|-------------|
337
+ | JSON | βœ… Free | Structured machine-readable findings |
338
+ | HTML | βœ… Free | Rich HTML report with NIST compliance table, severity badges, control matrix |
339
+ | Text | βœ… Free | Clean terminal-friendly text report |
340
+ | CycloneDX SBOM | βœ… Free | Industry-standard SBOM with findings as vulnerabilities |
341
+ | SPDX SBOM | βœ… Free | SPDX 2.3 document format |
342
+ | NIST 800-161 | βœ… Free | Control traceability matrix (SR-2.1 β†’ SR-11.4) |
343
+ | EU CRA | βœ… Free | Cyber Resilience Act article mapping |
344
+ | PDF | πŸ” Premium | Multi-page PDF with title page, findings table, NIST compliance matrix |
345
+ | Splunk CEF | πŸ” Premium | Common Event Format for Splunk ingestion |
346
+ | Elastic ECS | πŸ” Premium | Elastic Common Schema format |
347
+ | Microsoft Sentinel | πŸ” Premium | Sentinel-ready formatted output |
348
+ | IBM QRadar | πŸ” Premium | QRadar DSM-ready format with QID mappings |
349
+
350
+ ### Sample output
351
+
352
+ ```json
353
+ {
354
+ "scanId": 1,
355
+ "findings": [
356
+ {
357
+ "id": "ATK-003",
358
+ "severity": "high",
359
+ "title": "Credential harvesting",
360
+ "evidence": "process.env.NPM_TOKEN detected in postinstall.js:17"
361
+ }
362
+ ]
363
+ }
364
+ ```
365
+
366
+ ---
367
+
368
+ ## βš™οΈ Configuration & Advanced Usage
369
+
370
+ ### Policy-as-code
371
+
372
+ Define allowlists, severity overrides, suppressions, and fail thresholds in a YAML file:
373
+
374
+ ```yaml
375
+ # .npm-scan.yml
376
+ allowlist:
377
+ - lodash
378
+ - chalk
379
+
380
+ severity_overrides:
381
+ - id: ATK-001
382
+ severity: medium
383
+
384
+ suppress:
385
+ - atk_id: ATK-009
386
+ - package: some-package
387
+
388
+ fail_on: high
389
+ ```
390
+
391
+ ```bash
392
+ npm-scan scan target --policy .npm-scan.yml
393
+ ```
394
+
395
+ ### Environment variables
396
+
397
+ | Variable | Description | Default |
398
+ |----------|-------------|---------|
399
+ | `NPM_SCAN_LICENSE_KEY` | Premium / enterprise license key | β€” |
400
+ | `NPM_SCAN_DATA_DIR` | Scan history directory | `./.npm-scan` |
401
+ | `NPM_SCAN_LOG_LEVEL` | Log verbosity | `info` |
402
+ | `NPM_SCAN_LICENSE_SECRET` | HMAC key for license generation/validation | `npm-scan-default-dev-key` |
403
+
404
+ ### IOC configuration
405
+
406
+ Campaign detectors use seed IOC files for known-malicious fingerprints:
407
+
408
+ | IOC File | Detector | Types |
409
+ |----------|----------|-------|
410
+ | `backend/detectors/mini-shai-hulud/iocs.json` | Mini Shai-Hulud (Waves 1–3) | `packageScope`, `publisherAccount`, `sha512`, `extensionId` |
411
+ | `backend/detectors/trapdoor/iocs.json` | TrapDoor | `publisherAccount`, `campaignMarker`, `payloadFilename`, `payloadSize`, `xorKey`, `c2Domain`, `gistDomain` |
412
+ | `backend/detectors/node-ipc-compromise/iocs.json` | node-ipc compromise | `publisherAccount`, `c2Domain`, `c2IP`, `exfilZone`, `payloadHash` |
413
+ | `backend/detectors/msh-supplement/` | MSH Supplement | `obfuscationPattern`, `persistenceApi`, `targetedLocale`, `c2Keyword` |
414
+ | `backend/detectors/typosquat-vpmdhaj/` | Typosquat vpmdhaj | `blockedMaintainer`, `typosquatTarget`, `loaderPattern`, `credTarget` |
415
+ | `backend/detectors/axios-poisoning/` | Axios Poisoning | `blockedVersion`, `decoyDependency`, `ratPlatform`, `ratApi` |
416
+ | `backend/vsix-scan/vsix-iocs.json` | VSIX extension scan | `extensionId`, `publisherAccount`, `orphanCommitHash` |
417
+
418
+ 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.
419
+
420
+ ### Premium licensing
421
+
422
+ Contact leo@lateos.ai for a premium/enterprise license key.
423
+
424
+ ```bash
425
+ # Use it
426
+ npm-scan scan target --license-key <key>
427
+ npm-scan report --pdf --license-key <key>
428
+ npm-scan report --siem cef --license-key <key>
429
+ ```
430
+
431
+ ---
432
+
433
+ ## πŸ”— Integrations
434
+
435
+ ### GitHub Actions CI (for this repo)
436
+
437
+ Every push and PR runs tests across Node 18, 20, and 22:
438
+
439
+ ```yaml
440
+ # .github/workflows/ci.yml
441
+ name: CI
442
+ on:
443
+ push:
444
+ branches: [ main ]
445
+ pull_request:
446
+ branches: [ main ]
447
+ jobs:
448
+ test:
449
+ runs-on: ubuntu-latest
450
+ strategy:
451
+ matrix:
452
+ node-version: [18, 20, 22]
453
+ steps:
454
+ - uses: actions/checkout@v4
455
+ - uses: actions/setup-node@v4
456
+ with:
457
+ node-version: ${{ matrix.node-version }}
458
+ cache: 'npm'
459
+ - run: npm ci
460
+ - run: npm test
461
+ - run: npm run test:coverage
462
+ - run: node --test test/detectors-corpus.test.js
463
+ - run: npm run lint
464
+ - run: npm run build
465
+ ```
466
+
467
+ ### GitHub Action (for downstream users)
468
+
469
+ Scan your project's `package-lock.json` on every PR β€” detects typosquats, obfuscated payloads, credential harvesters, and worm propagation before they reach production. **SARIF output shows findings directly in GitHub's Security tab (Code Scanning).**
470
+
471
+ ```yaml
472
+ # .github/workflows/scan.yml
473
+ name: npm-scan
474
+ on:
475
+ pull_request:
476
+ paths:
477
+ - 'package-lock.json'
478
+ - '**/package.json'
479
+ jobs:
480
+ scan:
481
+ runs-on: ubuntu-latest
482
+ steps:
483
+ - uses: actions/checkout@v4
484
+ - uses: lateos/npm-scan@v1
485
+ with:
486
+ scan-type: lockfile
487
+ sarif: results.sarif
488
+ fail-on: high
489
+ - name: Upload SARIF to Security tab
490
+ uses: github/codeql-action/upload-sarif@v3
491
+ with:
492
+ sarif_file: results.sarif
493
+ ```
494
+
495
+ #### Action inputs
496
+
497
+ | Input | Default | Description |
498
+ |-------|---------|-------------|
499
+ | `scan-type` | `lockfile` | `lockfile` to scan `package-lock.json` or `package` to scan a specific npm package |
500
+ | `package` | β€” | Package name (required when `scan-type=package`) |
501
+ | `fail-on` | `high` | Fail the workflow at this severity threshold: `none`, `low`, `medium`, `high`, `critical` |
502
+ | `policy-file` | β€” | Path to a YAML/JSON policy file for allowlists, severity overrides, and suppressions |
503
+ | `license-key` | β€” | Premium license key for SIEM export and PDF reports |
504
+ | `siem-format` | β€” | SIEM output: `cef`, `ecs`, `sentinel`, `qradar` (premium) |
505
+ | `sbom-format` | β€” | SBOM output: `json`, `xml`, `spdx` |
506
+
507
+ #### Action outputs
508
+
509
+ | Output | Description |
510
+ |--------|-------------|
511
+ | `findings-count` | Number of findings detected |
512
+ | `scan-id` | Scan ID for later reference in reports |
513
+
514
+ #### Example: scan a specific package with policy + SBOM
515
+
516
+ ```yaml
517
+ - uses: lateos/npm-scan@v1
518
+ with:
519
+ scan-type: package
520
+ package: lodash
521
+ policy-file: .npm-scan.yml
522
+ sbom-format: spdx
523
+ fail-on: critical
524
+ ```
525
+
526
+ #### Example: scan with SIEM export (premium)
527
+
528
+ ```yaml
529
+ - uses: lateos/npm-scan@v1
530
+ with:
531
+ scan-type: lockfile
532
+ siem-format: cef
533
+ license-key: ${{ secrets.NPM_SCAN_LICENSE_KEY }}
534
+ ```
535
+
536
+ ### CI/CD pipeline
537
+
538
+ Integrate directly into your existing pipeline without the composite action:
539
+
540
+ ```bash
541
+ # Scan lockfile, fail build on high severity
542
+ npm-scan scan-lockfile --policy .npm-scan.yml || exit 1
543
+
544
+ # Scan a specific package, fail on critical only
545
+ npm-scan scan lodash --policy .npm-scan.yml || exit 1
546
+
547
+ # Generate SBOM as a build artifact
548
+ npm-scan scan express --sbom spdx > express-sbom.spdx.json
549
+
550
+ # Generate HTML compliance report in CI
551
+ npm-scan report --html > report.html
552
+
553
+ # Upload report as an artifact
554
+ # uses: actions/upload-artifact@v4
555
+ # with:
556
+ # name: npm-scan-report
557
+ # path: report.html
558
+ ```
559
+
560
+ ### Docker
561
+
562
+ See the [Docker quick-start section](#-run-lateosnpm-scan-anywhere-with-docker--zero-installation) above for pull commands, Compose pipeline, and multi-arch images.
563
+
564
+ Scan your project's `package-lock.json` on every PR β€” detects typosquats, obfuscated payloads, credential harvesters, and worm propagation before they reach production:
565
+
566
+ ```yaml
567
+ # .github/workflows/scan.yml
568
+ name: npm-scan
569
+ on:
570
+ pull_request:
571
+ paths:
572
+ - 'package-lock.json'
573
+ - '**/package.json'
574
+ jobs:
575
+ scan:
576
+ runs-on: ubuntu-latest
577
+ steps:
578
+ - uses: actions/checkout@v4
579
+ - uses: actions/setup-node@v4
580
+ with:
581
+ node-version: 20
582
+ - name: Scan lockfile
583
+ uses: lateos/npm-scan@v1
584
+ with:
585
+ scan-type: lockfile
586
+ fail-on: high
587
+ ```
588
+
589
+ #### Action inputs
590
+
591
+ | Input | Default | Description |
592
+ |-------|---------|-------------|
593
+ | `scan-type` | `lockfile` | `lockfile` to scan `package-lock.json` or `package` to scan a specific npm package |
594
+ | `package` | β€” | Package name (required when `scan-type=package`) |
595
+ | `fail-on` | `high` | Fail the workflow at this severity threshold: `none`, `low`, `medium`, `high`, `critical` |
596
+ | `policy-file` | β€” | Path to a YAML/JSON policy file for allowlists, severity overrides, and suppressions |
597
+ | `license-key` | β€” | Premium license key for SIEM export and PDF reports |
598
+ | `siem-format` | β€” | SIEM output: `cef`, `ecs`, `sentinel`, `qradar` (premium) |
599
+ | `sbom-format` | β€” | SBOM output: `json`, `xml`, `spdx` |
600
+
601
+ #### Action outputs
602
+
603
+ | Output | Description |
604
+ |--------|-------------|
605
+ | `findings-count` | Number of findings detected |
606
+ | `scan-id` | Scan ID for later reference in reports |
607
+
608
+ #### Example: scan a specific package with policy + SBOM
609
+
610
+ ```yaml
611
+ - uses: lateos/npm-scan@v1
612
+ with:
613
+ scan-type: package
614
+ package: lodash
615
+ policy-file: .npm-scan.yml
616
+ sbom-format: spdx
617
+ fail-on: critical
618
+ ```
619
+
620
+ #### Example: scan with SIEM export (premium)
621
+
622
+ ```yaml
623
+ - uses: lateos/npm-scan@v1
624
+ with:
625
+ scan-type: lockfile
626
+ siem-format: cef
627
+ license-key: ${{ secrets.NPM_SCAN_LICENSE_KEY }}
628
+ ```
629
+
630
+ ### CI/CD pipeline
631
+
632
+ Integrate directly into your existing pipeline without the composite action:
633
+
634
+ ```bash
635
+ # Scan lockfile, fail build on high severity
636
+ npm-scan scan-lockfile --policy .npm-scan.yml || exit 1
637
+
638
+ # Scan a specific package, fail on critical only
639
+ npm-scan scan lodash --policy .npm-scan.yml || exit 1
640
+
641
+ # Generate SBOM as a build artifact
642
+ npm-scan scan express --sbom spdx > express-sbom.spdx.json
643
+
644
+ # Generate HTML compliance report in CI
645
+ npm-scan report --html > report.html
646
+
647
+ # Upload report as an artifact
648
+ # uses: actions/upload-artifact@v4
649
+ # with:
650
+ # name: npm-scan-report
651
+ # path: report.html
652
+ ```
653
+
654
+ ### Pre-commit hook
655
+
656
+ Block supply chain threats **before** they reach version control β€” no CI required.
657
+
658
+ ```bash
659
+ # One-liner install (requires Node 18+, Git)
660
+ npx husky@latest init && npm install && npx husky add .husky/pre-commit "npx lint-staged"
661
+ ```
662
+
663
+ **What it does:** On every `git commit`, lint-staged detects staged changes to `package.json` or `package-lock.json` and runs `npm-scan scan-lockfile --fail-on high`. Commits are blocked if threats are found.
664
+
665
+ ```bash
666
+ $ git commit -m "bump lodash"
667
+ βœ” Preparing lint-staged configuration...
668
+ βœ” Running tasks for staged package*.json files...
669
+ βœ” npm-scan scan-lockfile --fail-on high
670
+ πŸ”΄ ATK-003: Credential exfiltration (DNS lookup to credentialharvest.example.com)
671
+ πŸ”΄ ATK-007: Typosquat detected (lodash@7.7.7)
672
+ ⚠ Exiting with code 1 β€” threat(s) found
673
+
674
+ npm scan β€’ @lateos/npm-scan v0.11.6
675
+ error: Command failed with exit code 1.
676
+ ```
677
+
678
+ Add `--no-verify` to bypass for emergencies (`git commit -m "emergency fix" --no-verify`).
679
+
680
+ ### Docker
681
+
682
+ See the [Docker quick-start section](#-run-lateosnpm-scan-anywhere-with-docker--zero-installation) above for pull commands, Compose pipeline, and multi-arch images.
683
+
684
+ ---
685
+
686
+ ## πŸ—ΊοΈ Roadmap & Enterprise Features
687
+
688
+ ### Free tier (shipped)
689
+
690
+ - All 11 ATK detectors + **MEGALODON** CI/CD campaign detection (D1–D6) + **HF_IMPERSONATION** detector + **MINI_SHAI_HULUD** worm campaign (D1–D7, 3 waves, with **MSH_SUPPLEMENT** D1–D4 for obfuscation/persistence/geofence/C2) + **VSIX_SCAN** extension supply chain scan (6 detectors) + **CVE-2026-48710 (BadHost)** Python vulnerability detection (3 layers) + **TRAPDOOR** cross-ecosystem attack detection (9 rules) + **NODE_IPC_COMPROMISE** expired-domain hijack detection (11 rules) + **TYPOSQUAT_VPMDHAJ** mass typosquatting campaign (3 rules) + **AXIOS_POISONING** registry poisoning campaign (3 rules)
691
+ - SBOM output (CycloneDX + SPDX)
692
+ - HTML, text, and compliance reports (NIST + EU CRA)
693
+ - Policy-as-code engine (YAML)
694
+ - Local SQLite scan history
695
+ - GitHub Action
696
+ - Pre-commit hook (husky + lint-staged)
697
+ - Docker images + Compose pipeline
698
+ - Watch mode (--watch / --monorepo for auto-rescan)
699
+ - VS Code extension scanning (--vsix flag with Marketplace + Open VSX registries)
700
+
701
+ ### Premium (πŸ” license key)
702
+
703
+ - PDF compliance reports with NIST traceability matrix
704
+ - SIEM export (Splunk CEF, Elastic ECS, Microsoft Sentinel, IBM QRadar)
705
+ - Dynamic sandbox (gVisor-based β€” ATK-008–010)
706
+ - Reachability analysis (call graph filtering)
707
+
708
+ ### Enterprise (🏒 custom license)
709
+
710
+ - SAML 2.0 SSO (Okta, Azure AD, OneLogin, Keycloak)
711
+ - REST API + webhooks (FastAPI)
712
+ - Team RBAC + audit logs
713
+ - Helm chart for Kubernetes deployment
714
+ - PostgreSQL backend for hosted/team tier
715
+ - SLA-backed priority support
716
+
717
+ ---
718
+
719
+ ## 🀝 Contributing
720
+
721
+ We welcome contributions β€” especially new detectors, improved evasion resistance, and compliance templates.
722
+
723
+ See [`docs/attack-taxonomy.md`](docs/attack-taxonomy.md) for the ATK governance process. Every new detector requires:
724
+
725
+ 1. A proof-of-concept sample
726
+ 2. A detection rule with tests
727
+ 3. False-positive analysis on top-500 npm packages
728
+ 4. NIST 800-161 control mapping
729
+
730
+ ### Testing
731
+
732
+ The project uses the **Node.js native test runner** (`node:test` + `assert/strict`).
733
+
734
+ ```bash
735
+ # Run all tests
736
+ npm test
737
+
738
+ # Run tests with coverage
739
+ npm run test:coverage
740
+
741
+ # Run tests with verbose spec output
742
+ npm run test:verbose
743
+
744
+ # Run local malicious/clean corpus (no network needed)
745
+ node --test test/detectors-corpus.test.js
746
+ ```
747
+
748
+ **Test structure:**
749
+ - `test/fixtures/mock-data.js` β€” shared mock scans, packages, and code snippets
750
+ - `test/megalodon.test.js` β€” 30 Megalodon campaign detection tests (D1–D4 + aggregator + runAll integration)
751
+ - `test/db.test.js` β€” database CRUD (save, query, persist)
752
+ - `test/detectors-edge-cases.test.js` β€” per-detector boundary tests (no-ops, clean clears, severity)
753
+ - `test/detectors-corpus.test.js` β€” 33 malicious + 50 clean tarball integration (offline)
754
+ - `test/fetch.test.js` β€” tarball extraction, temp directory cleanup
755
+ - `test/policy-edge-cases.test.js` β€” edge cases in suppress, override, load validation
756
+ - `test/policy.test.js` β€” policy YAML/JSON load, apply, suppress, severity override tests
757
+ - `test/report-snapshots.test.js` β€” HTML/text/CRA/PDF format assertions
758
+ - `test/report.test.js` β€” SARIF, CSV, STIG, risk score format tests
759
+ - `test/lockfile.test.js` β€” npm/yarn/pnpm parser, auto-detect, ATK-007/011 lockfile tests
760
+ - `test/hf-impersonation.test.js` β€” 13 HF impersonation detection tests (no-ref, exact match, spoof, README clone, artifact mismatch, postinstall escalation, new-org tag)
761
+ - `test/mini-shai-hulud.test.js` β€” 22 Mini Shai-Hulud worm campaign detection tests (burst, sibling, SLSA, maintainer, IOC, exfil, wave attribution)
762
+ - `test/vsix-scan/burst-publish.test.js` β€” 4 VSIX burst publish tests (threshold, sub-threshold, hot-pull, Open VSX window)
763
+ - `test/vsix-scan/publisher-anomaly.test.js` β€” 5 publisher anomaly tests (cross-namespace, new-account, add+publish, substitution, silent)
764
+ - `test/vsix-scan/activation-event-risk.test.js` β€” 5 activation event risk tests (onStartupFinished, wildcard, escalation, first-time, silent)
765
+ - `test/vsix-scan/orphan-commit-fetch.test.js` β€” 5 orphan commit tests (GitHub SHA, npx git, MCP exfil, Bun install, silent)
766
+ - `test/vsix-scan/known-ioc.test.js` β€” 4 known IOC tests (extensionId, publisher window, outside window)
767
+ - `test/vsix-scan/exfil-pattern.test.js` β€” 5 exfil pattern tests (creds, DNS tunnel, AES+RSA, anti-analysis, silent)
768
+ - `test/vsix-scan/integration.test.js` β€” 4 integration tests (Nx Console CRITICAL, safe version clean, orphan commit, skipNetwork)
769
+ - `test/cve-2026-48710-badhost/manifest.test.js` β€” 13 Python manifest parsing tests (requirements.txt, pyproject.toml, poetry.lock, version edge cases)
770
+ - `test/cve-2026-48710-badhost/transitive.test.js` β€” 7 transitive dependency tests (Tier 1/2, fastapi version gating, pin suppression)
771
+ - `test/cve-2026-48710-badhost/codePattern.test.js` β€” 6 static code pattern tests (auth context, INFO fallthrough, scope suppression)
772
+ - `test/cve-2026-48710-badhost/integration.test.js` β€” 4 integration tests (end-to-end composite findings, clean project, no Python files)
773
+ - `test/trapdoor.test.js` β€” 40 TrapDoor campaign detection tests (D1–D9: campaign marker, payload fingerprint, publisher blocklist, Gist exfil, AI poisoning, lure name, crypto primitives, XOR key, credential validation)
774
+ - `test/node-ipc.test.js` β€” 37 node-ipc compromise detection tests (D1–D11: version blocklist, tarball hash, CJS injection, payload hash, DNS C2 pattern, bootstrap resolver, DNS TXT exfil, runtime trigger, temp artifact, unauthorized publisher, blast radius)
775
+ - `test/msh-supplement.test.js` β€” 17 MSH supplement tests (ctf-scramble-v2 stop, daemonization, geo killswitch, C2 dead-drop, provenance, false positives)
776
+ - `test/typosquat-vpmdhaj.test.js` β€” 16 typosquatting campaign tests (maintainer block, prefix detection, levenshtein, preinstall stagers, Bun loader, AWS/ECS/Vault/GitHub cred exfil)
777
+ - `test/axios-poisoning.test.js` β€” 13 axios poisoning tests (version blocklist stop, decoy dependency, crypto heuristic, cross-platform RAT, C2 callback)
778
+ - `test/cli.test.js` β€” commander integration tests (help, version, scan, report, error handling)
779
+ - `test/cli-lockfile.test.js` β€” scan-lockfile CLI options, yarn/pnpm/monorepo/watch tests
780
+
781
+ ### Need help?
782
+
783
+ - πŸ”’ See [security policy](SECURITY.md) for vulnerability disclosure
784
+ - πŸ“– Read the [project plan](docs/project-plan.md)
785
+ - 🧬 Review the [attack taxonomy](docs/attack-taxonomy.md)
786
+ - πŸ› Open an issue or PR
787
+
788
+ ---
789
+
790
+ ## πŸ“„ License
791
+
792
+ Apache-2.0 core + Commons Clause.
793
+ See [`LICENSING.md`](LICENSING.md) for the exact boundary between free and premium features.
794
+
795
+ ---
796
+
797
+ ## πŸ‘€ About the Maintainer
798
+
799
+ **Roongrunchai Chongolnee** β€” creator and maintainer of `@lateos/npm-scan`. Certified security professional (CISSP, CEH, Cisco Security, AWS Cloud Practitioner) with a decade of infrastructure and application security experience at Philips. I built this tool to give the open-source community a practical, detector-driven defense against supply-chain malware β€” and I'm committed to keeping it transparent, community-owned, and continuously improved.
800
+
801
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-0A66C2?style=flat-square&logo=linkedin)](https://www.linkedin.com/in/roongrunchai-chong-c-ab9742108/)
802
+ [![GitHub](https://img.shields.io/badge/GitHub-lateos--ai-181717?style=flat-square&logo=github)](https://github.com/lateos-ai/npm-scan)
803
+
804
+ Issues, ideas, and pull requests are always welcome β€” security is strongest when we collaborate.
805
+
806
+ ---
807
+
808
+ ```
809
+ @lateos/npm-scan β€” npm supply chain security scanner
810
+ Copyright (C) 2026 Lateos
811
+
812
+ Licensed under the Apache License, Version 2.0 (the "License");
813
+ you may not use this file except in compliance with the License.
814
+
815
+ Unless required by applicable law or agreed to in writing, software
816
+ distributed under the License is distributed on an "AS IS" BASIS,
817
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
818
+ ```
819
+
820
+ ---
821
+
822
+ **Scan your first package now:**
823
+
824
+ ```bash
825
+ npx @lateos/npm-scan scan lodash
826
+ ```