chain-audit 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,10 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Node.js Version](https://img.shields.io/node/v/chain-audit.svg)](https://nodejs.org)
7
7
 
8
- **Fast, zero-dependency CLI to detect supply chain attacks in `node_modules`.**
8
+ **Zero-dependency heuristic scanner CLI to detect supply chain attacks in `node_modules`.**
9
+
10
+ > **Disclaimer:** chain-audit is a **heuristic scanner** that searches for suspicious patterns in code. It does **not** detect 100% confirmed attacks, but rather flags potentially suspicious behavior that requires **human analysis**. The tool may produce **false positives** (flagging legitimate code as suspicious) and **false negatives** (missing real attacks). It's up to you to review and determine whether findings are actually suspicious or legitimate. Always investigate findings before taking action.
11
+ > Licensed under **MIT License**, provided "AS IS" without warranty of any kind.
9
12
 
10
13
  ---
11
14
 
@@ -20,9 +23,9 @@
20
23
  | Detects obfuscated code | ✅ | ❌ |
21
24
  | Zero dependencies | ✅ | N/A |
22
25
  | Works offline | ✅ | ❌ |
23
- | SARIF output (GitHub integration) | ✅ | ❌ |
26
+ | SARIF output (GitHub integration) [experimental] | ✅ | ❌ |
24
27
 
25
- **Use both together** – `npm audit` for known vulnerabilities, `chain-audit` for detecting novel attacks.
28
+ **Use both together** – `npm audit` for known vulnerabilities, `chain-audit` (heuristic scanner) for detecting novel attacks and suspicious patterns.
26
29
 
27
30
  ## Installation
28
31
 
@@ -69,7 +72,10 @@ bun build src/index.js --compile --outfile chain-audit
69
72
  ## Quick Start
70
73
 
71
74
  ```bash
72
- # Scan current project
75
+ # Recommended: Thorough scan with detailed analysis
76
+ chain-audit --scan-code --detailed
77
+
78
+ # Scan current project (basic scan)
73
79
  chain-audit
74
80
 
75
81
  # Fail CI on high severity issues
@@ -84,7 +90,7 @@ chain-audit --severity critical,high --fail-on high
84
90
  # JSON output for processing
85
91
  chain-audit --json
86
92
 
87
- # SARIF output for GitHub Code Scanning
93
+ # SARIF output for GitHub Code Scanning (experimental)
88
94
  chain-audit --sarif > results.sarif
89
95
 
90
96
  # Deep code analysis (slower but more thorough)
@@ -97,7 +103,7 @@ chain-audit --detailed --scan-code
97
103
  chain-audit --detailed --json --scan-code
98
104
 
99
105
  # Ignore specific packages and rules
100
- chain-audit --ignore-packages "@types/*" --ignore-rules native_binary
106
+ chain-audit --ignore-packages "@types/*" --ignore-rules native_binary,executable_files
101
107
 
102
108
  # Additional structure integrity checks
103
109
  chain-audit --verify-integrity --fail-on high
@@ -120,7 +126,7 @@ chain-audit --check-typosquatting
120
126
  | `-l, --lock <path>` | Path to lockfile (auto-detects npm, yarn, pnpm, bun) |
121
127
  | `-c, --config <path>` | Path to config file (auto-detects if not specified) |
122
128
  | `--json` | Output as JSON |
123
- | `--sarif` | Output as SARIF (for GitHub Code Scanning) |
129
+ | `--sarif` | Output as SARIF (for GitHub Code Scanning) [experimental] |
124
130
  | `-s, --severity <levels>` | Show only specified severity levels (comma-separated, e.g., `critical,high`) |
125
131
  | `--fail-on <level>` | Exit 1 if max severity >= level |
126
132
  | `--scan-code` | Deep scan JS files for suspicious patterns |
@@ -131,7 +137,7 @@ chain-audit --check-typosquatting
131
137
  | `-f, --force` | Force overwrite existing config file (use with `--init`) |
132
138
  | **Filtering Options** | |
133
139
  | `-I, --ignore-packages <list>` | Ignore packages (comma-separated, supports globs, e.g., `@types/*,lodash`) |
134
- | `-R, --ignore-rules <list>` | Ignore rule IDs (comma-separated, e.g., `native_binary,install_script`) |
140
+ | `-R, --ignore-rules <list>` | Ignore rule IDs (comma-separated, e.g., `native_binary,executable_files,install_script`) |
135
141
  | `-T, --trust-packages <list>` | Trust packages (comma-separated, supports globs, e.g., `esbuild,@swc/*`) |
136
142
  | **Scan Options** | |
137
143
  | `--max-file-size <bytes>` | Max file size to scan (default: 1048576 = 1MB) |
@@ -145,11 +151,11 @@ chain-audit --check-typosquatting
145
151
 
146
152
  | Level | Description | Example |
147
153
  |-------|-------------|---------|
148
- | `critical` | Highly likely malicious | Obfuscated code with network access, extraneous packages |
154
+ | `critical` | Highly likely malicious | Obfuscated code with network access, version mismatch |
149
155
  | `high` | Strong attack indicators | Suspicious install scripts with network/exec, typosquatting |
150
156
  | `medium` | Warrants investigation | Install scripts, shell execution patterns |
151
157
  | `low` | Informational | Native binaries, minimal metadata |
152
- | `info` | Metadata only | Packages with install scripts that match trusted patterns (if configured) |
158
+ | `info` | Metadata only | Packages with install scripts that are in trusted packages list (if configured) |
153
159
 
154
160
  ### Filtering by Severity
155
161
 
@@ -169,12 +175,13 @@ chain-audit --severity low,medium
169
175
  chain-audit --severity critical,high --fail-on high
170
176
  ```
171
177
 
172
- Issues will be displayed in the order they are found, grouped by the severity levels you specified.
178
+ Issues will be displayed sorted by severity (highest first), then by package name, grouped by severity level. When using `--severity`, only the specified severity levels are shown.
173
179
 
174
180
  ## Example Output
175
181
 
176
182
  ```
177
- chain-audit v0.6.1
183
+ chain-audit v0.6.3
184
+ Zero-dependency heuristic scanner CLI to detect supply chain attacks in node_modules
178
185
  ────────────────────────────────────────────────────────────
179
186
 
180
187
  node_modules: /path/to/project/node_modules
@@ -186,9 +193,9 @@ Found 3 potential issue(s):
186
193
 
187
194
  ── CRITICAL ──
188
195
  ● evil-package@1.0.0
189
- reason: extraneous_package
190
- detail: Package exists in node_modules but is missing from lockfile
191
- fix: Run `npm ci` to reinstall from lockfile
196
+ reason: version_mismatch
197
+ detail: Installed version 1.0.0 does not match lockfile version 0.9.5
198
+ fix: Run `npm ci` to reinstall correct version
192
199
 
193
200
  ── HIGH ──
194
201
  ● suspic-lib@2.0.0
@@ -198,9 +205,9 @@ Found 3 potential issue(s):
198
205
 
199
206
  ── MEDIUM ──
200
207
  ● some-addon@1.2.3
201
- reason: install_script
202
- detail: Has postinstall script: node-gyp rebuild
203
- fix: Review the script to ensure it performs only expected operations
208
+ reason: extraneous_package
209
+ detail: Package exists in node_modules but is missing from lockfile
210
+ fix: Run `npm ci` to reinstall from lockfile
204
211
 
205
212
  ────────────────────────────────────────────────────────────
206
213
  Summary:
@@ -223,10 +230,10 @@ When `--detailed` is enabled, each finding includes:
223
230
  - **Matched patterns** (regex) that triggered the detection
224
231
  - **Package metadata**: author, repository URL, license, homepage, full file path
225
232
  - **Trust assessment**: trust score (0-100) and trust level (low/medium/high)
226
- - **Evidence**: file paths, line numbers, column numbers, matched text
233
+ - **Evidence**: file paths, line numbers, column numbers (in matches array), matched text
227
234
  - **False positive hints**: guidance on legitimate uses that might trigger the detection
228
- - **Verification steps**: actionable steps for manual investigation
229
- - **Risk assessment**: for critical findings, notes about known attack patterns (e.g., Shai-Hulud 2.0)
235
+ - **Verification steps**: actionable steps for manual investigation (available for some findings like typosquatting)
236
+ - **Risk assessment**: for high/critical findings, notes about known attack patterns
230
237
 
231
238
  ### Trust Score Calculation
232
239
 
@@ -234,17 +241,17 @@ The trust score (0-100) is calculated based on multiple factors:
234
241
 
235
242
  | Factor | Points | Description |
236
243
  |--------|--------|-------------|
237
- | **Trusted scope** | +40 | Package is from a scope listed in `trustedPackages` config (if configured) |
238
- | **Known legitimate** | +50 | Package is in the `trustedPackages` config list (if configured) |
244
+ | **Trusted scope** | +40 | Package is from a scope in the internal trusted scopes list (currently empty by default) |
245
+ | **Known legitimate** | +50 | Package is in the internal known legitimate packages list (currently empty by default) |
239
246
  | **Has repository** | +20 | Package has a repository URL in package.json |
240
247
  | **Has homepage** | +10 | Package has a homepage URL |
241
248
  | **Has author** | +10 | Package has author information |
242
249
  | **Has license** | +10 | Package has a license field |
243
250
 
244
- **Note:** By default, no packages are whitelisted. All packages are checked with equal severity. You can configure `trustedPackages` in `.chainauditrc.json` if you need to reduce false positives for specific packages.
251
+ **Note:** Trust score is calculated independently from the `trustedPackages` config option. The `trustedPackages` config option affects severity levels for install scripts, but does not influence the trust score calculation. By default, no packages are whitelisted in the trust score calculation. All packages are checked with equal severity.
245
252
 
246
253
  **Trust Levels:**
247
- - **High (70-100)**: Package is likely legitimate (e.g., configured as trusted with repository)
254
+ - **High (70-100)**: Package is likely legitimate (e.g., has repository, homepage, author, and license)
248
255
  - **Medium (40-69)**: Package has some trust indicators but needs verification
249
256
  - **Low (0-39)**: Package lacks trust indicators, warrants closer investigation
250
257
 
@@ -306,10 +313,12 @@ Alternatively, you can manually create a config file in your project root. Suppo
306
313
  ],
307
314
  "trustedPatterns": {
308
315
  "node-gyp rebuild": true,
309
- "prebuild-install": true
316
+ "prebuild-install": true,
317
+ "node-pre-gyp": true
310
318
  },
311
319
  "scanCode": false,
312
320
  "checkTyposquatting": false,
321
+ "checkLockfile": false,
313
322
  "failOn": "high",
314
323
  "severity": ["critical", "high"],
315
324
  "format": "text",
@@ -331,9 +340,10 @@ Alternatively, you can manually create a config file in your project root. Suppo
331
340
  | `trustedPatterns` | `object` | `{node-gyp rebuild: true, ...}` | Install script patterns considered safe |
332
341
  | `scanCode` | `boolean` | `false` | Enable deep code scanning by default |
333
342
  | `checkTyposquatting` | `boolean` | `false` | Enable typosquatting detection (disabled by default to reduce false positives) |
343
+ | `checkLockfile` | `boolean` | `false` | Enable lockfile integrity checks (disabled by default due to possible false positives) |
334
344
  | `failOn` | `string` | `null` | Default fail threshold (`info\|low\|medium\|high\|critical`) |
335
345
  | `severity` | `string[]` | `null` | Show only specified severity levels (e.g., `["critical", "high"]`) |
336
- | `format` | `string` | `"text"` | Output format: `text`, `json`, or `sarif` |
346
+ | `format` | `string` | `"text"` | Output format: `text`, `json`, or `sarif` (sarif is experimental) |
337
347
  | `verbose` | `boolean` | `false` | Show detailed analysis with code snippets and trust scores (Note: CLI flag is `--detailed`, but config uses `verbose` for consistency) |
338
348
  | `maxFileSizeForCodeScan` | `number` | `1048576` | Max file size (bytes) to scan for code patterns |
339
349
  | `maxNestedDepth` | `number` | `10` | Max depth to traverse nested node_modules |
@@ -372,7 +382,7 @@ jobs:
372
382
  run: npm rebuild
373
383
  ```
374
384
 
375
- ### With SARIF Upload (GitHub Code Scanning)
385
+ ### With SARIF Upload (GitHub Code Scanning) [experimental]
376
386
 
377
387
  ```yaml
378
388
  name: Security Scan
@@ -427,9 +437,9 @@ jobs:
427
437
 
428
438
  **Available inputs:**
429
439
  - `node-modules-path` (default: `./node_modules`) – Path to node_modules directory
430
- - `fail-on` (default: `high`) – Severity threshold to fail on (info|low|medium|high|critical)
440
+ - `fail-on` (default: `critical`) – Severity threshold to fail on (info|low|medium|high|critical)
431
441
  - `scan-code` (default: `false`) – Enable deep code scanning (slower)
432
- - `upload-sarif` (default: `true`) – Upload SARIF to GitHub Code Scanning
442
+ - `upload-sarif` (default: `true`) – Upload SARIF to GitHub Code Scanning [experimental]
433
443
 
434
444
  The reusable workflow automatically uses `--ignore-scripts` for safe installation.
435
445
 
@@ -448,7 +458,7 @@ The reusable workflow automatically uses `--ignore-scripts` for safe installatio
448
458
 
449
459
  ### CI/CD Security Best Practices
450
460
 
451
- Supply chain attacks like [Shai-Hulud 2.0](https://www.wiz.io/blog/shai-hulud-2-0-aftermath-ongoing-supply-chain-attack) exploited misconfigured GitHub Actions. **Protect your CI/CD:**
461
+ Supply chain attacks have exploited misconfigured GitHub Actions. **Protect your CI/CD:**
452
462
 
453
463
  ```yaml
454
464
  # DANGEROUS - Don't use pull_request_target with checkout
@@ -479,44 +489,52 @@ chain-audit automatically detects and parses:
479
489
 
480
490
  | Lockfile | Package Manager |
481
491
  |----------|-----------------|
482
- | `package-lock.json` | npm v2/v3 |
483
- | `npm-shrinkwrap.json` | npm |
492
+ | `package-lock.json` | npm v2/v3 (v1 supported as fallback) |
493
+ | `npm-shrinkwrap.json` | npm (v1/v2/v3) |
484
494
  | `yarn.lock` | Yarn Classic & Berry |
485
495
  | `pnpm-lock.yaml` | pnpm |
486
- | `bun.lock` | Bun |
496
+ | `bun.lock` | Bun (text format) |
497
+ | `bun.lockb` | Bun (binary format, not supported - use `bun install --save-text-lockfile` to generate text format) |
487
498
 
488
499
  ## Detection Rules
489
500
 
490
501
  ### Critical Severity
491
- - **extraneous_package** – Package in node_modules not in lockfile
492
- - **version_mismatch** – Installed version differs from lockfile
502
+ - **version_mismatch** – Installed version differs from lockfile (requires `--check-lockfile`)
503
+ - **pipe_to_shell** – Script pipes content to shell (`| bash`)
504
+ - **potential_env_exfiltration** – Env access + network in install script
505
+
506
+ ### High Severity
493
507
  - **corrupted_package_json** – Package has malformed or unreadable package.json
494
508
 
495
509
  ### High Severity (with `--verify-integrity`)
496
510
  - **package_name_mismatch** – Package name in package.json doesn't match expected from path
497
511
  - **suspicious_resolved_url** – Package resolved from local file or suspicious URL
498
- - **pipe_to_shell** – Script pipes content to shell (`| bash`)
499
- - **potential_env_exfiltration** – Env access + network in install script
500
- - **env_with_network** – Code accesses env vars and has network/exec capabilities
501
- - **obfuscated_code** – Base64/hex encoded strings, char code arrays
502
512
 
503
513
  ### High Severity
504
- - **network_access_script** – Install script with curl/wget/fetch patterns
514
+ - **network_access_script** – Install script with curl/wget/fetch patterns (high for install scripts, low for trusted install scripts, medium/low for others)
505
515
  - **potential_typosquat** – Package name similar to popular package (requires `--check-typosquatting`)
506
- - **suspicious_name_pattern** – Package name uses character substitution (l33t speak) (requires `--check-typosquatting`)
507
- - **eval_usage** – Code uses eval() or new Function()
508
- - **sensitive_path_access** – Code accesses ~/.ssh, ~/.aws, etc.
509
- - **shell_execution** – Script executes shell commands
516
+ - **suspicious_name_pattern** – Package name uses character substitution (l33t speak) or prefix patterns (requires `--check-typosquatting`) (high for character substitution, medium for prefix patterns)
517
+ - **eval_usage** – Code uses eval() or new Function() (requires `--scan-code`)
518
+ - **sensitive_path_access** – Code accesses ~/.ssh, ~/.aws, etc. (requires `--scan-code`)
519
+ - **shell_execution** – Script executes shell commands (high for install scripts, medium/low for others)
520
+
521
+ ### Critical Severity (with `--scan-code`)
522
+ - **obfuscated_code** – Base64/hex encoded strings, char code arrays
523
+
524
+ ### High Severity (with `--scan-code`)
525
+ - **env_with_network** – Code accesses env vars and has network/exec capabilities (critical severity, or medium for install scripts)
510
526
 
511
527
  ### Medium Severity
512
- - **install_script** – Has preinstall/install/postinstall/prepare script
513
- - **code_execution** – Script runs code via node -e, python -c, etc.
528
+ - **extraneous_package** – Package in node_modules not in lockfile (requires `--check-lockfile`)
529
+ - **install_script** – Has preinstall/install/postinstall script (medium, or info/low for trusted packages/patterns)
530
+ - **code_execution** – Script runs code via node -e, python -c, etc. (high for install scripts, medium/low for others)
514
531
  - **child_process_usage** – Code uses child_process module
515
532
  - **node_network_access** – Code uses Node.js network APIs (fetch, https, axios)
516
533
  - **git_operation_install** – Install script performs git operations
534
+ - **executable_files** – Contains executable files (shell scripts, etc.) - high if outside bin/, medium if in bin/
517
535
 
518
536
  ### Low/Info Severity
519
- - **native_binary** – Contains .node, .so, .dll, .dylib files
537
+ - **native_binary** – Contains native module binaries (.node, .so, .dylib files)
520
538
  - **no_repository** – No repository URL in package.json
521
539
  - **minimal_metadata** – Very short/missing description
522
540
 
@@ -525,11 +543,13 @@ chain-audit automatically detects and parses:
525
543
  ```javascript
526
544
  const { run } = require('chain-audit');
527
545
 
528
- const result = await run(['node', 'script.js', '--json', '--fail-on', 'high']);
546
+ const result = run(['node', 'script.js', '--json', '--fail-on', 'high']);
529
547
 
530
548
  console.log(result.exitCode); // 0 or 1
531
- console.log(result.issues); // Array of issues found
532
- console.log(result.summary); // { counts: {...}, maxSeverity: 'high' }
549
+ console.log(result.issues); // Array of all issues found (not filtered by --severity)
550
+ console.log(result.summary); // { counts: {...}, maxSeverity: 'high' } (calculated from filtered issues if --severity is used)
551
+
552
+ // Note: run() also outputs to console.log() by default. Use --json format to get structured output.
533
553
  ```
534
554
 
535
555
  ## Best Practices
@@ -565,7 +585,7 @@ npm rebuild
565
585
  3. **Run in sandboxed CI** – Isolate potentially malicious code
566
586
  4. **Combine with npm audit** – chain-audit detects different threats
567
587
  5. **Review all findings** – Some may be false positives
568
- 6. **Use `--scan-code` periodically** – More thorough but slower
588
+ 6. **Recommended: Use `--scan-code --detailed` for thorough analysis** – Deep code scanning with detailed evidence (slower but most comprehensive)
569
589
  7. **Use `--detailed` for manual investigation** – Get code snippets and trust assessment to distinguish false positives (`--verbose` is an alias)
570
590
  8. **Keep registry secure** – Use private registry or npm audit signatures
571
591
  9. **All packages are checked equally** – No packages are whitelisted by default. Even popular packages like `sharp`, `esbuild`, or `@babel/*` are checked for malicious patterns. This ensures that compromised packages are detected regardless of their reputation.
@@ -598,7 +618,13 @@ Hubert Kasperek
598
618
 
599
619
  ---
600
620
 
601
- **Disclaimer:** chain-audit is a heuristic scanner created for **educational and research purposes**, provided "AS IS" without warranty of any kind. It may produce false positives and **cannot catch all attacks**.
621
+ **Disclaimer:** chain-audit is a **heuristic scanner** created for **educational and research purposes**, licensed under **MIT License**, provided "AS IS" without warranty of any kind. The author makes no guarantees about the tool's accuracy, completeness, or reliability.
622
+
623
+ **Important limitations:**
624
+ - chain-audit does **not** detect 100% confirmed attacks – it scans code for suspicious patterns
625
+ - It may produce **many false positives** – findings require human analysis to determine if they're actually suspicious
626
+ - It **cannot catch all attacks** – sophisticated or novel attack patterns may be missed
627
+ - The tool flags potentially suspicious behavior, but **you are responsible** for reviewing and validating all findings
602
628
 
603
629
  **The author takes no responsibility for:**
604
630
  - False positives or false negatives in detection
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "chain-audit",
3
- "version": "0.6.1",
4
- "description": "Fast, zero-dependency CLI to detect supply chain attacks in node_modules. Scans for malicious install scripts, typosquatting, extraneous packages, and suspicious code patterns.",
3
+ "version": "0.6.3",
4
+ "description": "Zero-dependency heuristic scanner CLI to detect supply chain attacks in node_modules. Scans for malicious install scripts, typosquatting, extraneous packages, lockfile integrity, obfuscated code, executable files, and suspicious code patterns.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "chain-audit": "src/index.js"
@@ -31,17 +31,12 @@
31
31
  "keywords": [
32
32
  "security",
33
33
  "supply-chain",
34
- "supply-chain-attack",
35
- "node-modules",
36
- "audit",
37
- "malware",
38
34
  "dependency",
39
- "npm-audit",
40
- "postinstall",
41
- "typosquatting",
42
- "ci",
43
- "github-actions",
44
- "sarif"
35
+ "heuristic-scanner",
36
+ "lockfile",
37
+ "obfuscation",
38
+ "static-analysis",
39
+ "ci"
45
40
  ],
46
41
  "author": "Hubert Kasperek",
47
42
  "license": "MIT",