nsauditor-ai 0.1.30 → 0.1.32

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
@@ -15,6 +15,67 @@ NSAuditor AI is the open-source core of a privacy-first security intelligence pl
15
15
 
16
16
  **Zero Data Exfiltration by design.** NSAuditor AI works fully offline. AI analysis, CVE correlation, and continuous monitoring all happen locally. External calls (to AI APIs, NVD, etc.) are opt-in and use your own API keys. We never see your scan data.
17
17
 
18
+ ## What's New (0.1.32) — Claude Desktop integration overhaul + ground-truth diagnostics
19
+
20
+ The 0.1.32 line bundles three operational improvements driven by real customer-onboarding friction surfaced during the developer's own Claude Desktop integration test (2026-05-10):
21
+
22
+ - **`nsauditor-ai mcp install-key` now auto-generates a machine-specific Claude Desktop config snippet.** Reads `process.execPath` (the Node binary actually running) and derives the script path from `import.meta.url` — the printed JSON has absolute paths that work whether you're on system Node, homebrew, nvm, fnm, local-project install, Linux, or Windows. No install-type detective work, no PATH-misalignment failures. On macOS, the snippet uses `keychain:` indirection for **both** auth and license — secrets never land in the world-readable Claude Desktop config file.
23
+ - **License `keychain:` indirection.** `loadLicense()` and `resolveLicenseKey()` honor the `keychain:LABEL` prefix on the env-supplied value (mirrors the EE-SEC.1 MCP-auth pattern). Operators can put `"NSAUDITOR_LICENSE_KEY": "keychain:NSAUDITOR_LICENSE_KEY"` in their Claude Desktop env block; the JWT stays in macOS Keychain. Backward-compat: literal JWTs continue to work unchanged.
24
+ - **`nsauditor-ai mcp tier` ground-truth subcommand.** Customer-side check that prints the EXACT tier the spawned MCP server resolves to. We discovered Claude Desktop reports of "Current tier: CE" despite verified Pro/Enterprise license were caused by Claude (the AI) **synthesizing the tier text from training data + context** instead of actually calling `list_plugins` via MCP. The MCP server's resolution was always correct. `mcp tier` bypasses Claude's interpretive layer — paste the output into a support ticket to distinguish "MCP genuinely broken" from "Claude misreading."
25
+ - **MCP key rotation cadence (Thread I).** Optional 90-day rotation soft warning at server startup + `mcp status` (override via `NSA_MCP_AUTH_KEY_ROTATION_DAYS`, clamped to [7, 365]). SOC 2 CC6.1/CC6.7 reviewers expect a credential-rotation cadence; an unrotated MCP auth key is treated the same way as an unrotated IAM access key.
26
+ - **Keychain-locked vs Keychain-empty distinction.** New `keychain-locked` source variant in `mcp status` for headless macOS / SSH-only CI runners — instead of falling through silently to "unconfigured", operators get an actionable error with three GUI-free workarounds.
27
+ - **Atomic file writes** for `~/.nsauditor/.env` (`.tmp` + POSIX-rename) so concurrent readers + crash recovery never observe a truncated file.
28
+ - **Auto-mirror license file→Keychain on `mcp install-key`** (macOS) when the license is configured in `~/.nsauditor/.env` but absent from Keychain. Lets the printed snippet's `keychain:` indirection actually resolve, with original storage location preserved unchanged.
29
+
30
+ **Breaking change for existing 0.1.31 operators**: nothing breaks, but the recommended Claude Desktop config snippet has changed. Re-run `nsauditor-ai mcp install-key` after upgrading to get the new auto-generated snippet with absolute paths + license indirection. Old configs continue to work.
31
+
32
+ ```bash
33
+ npm install -g nsauditor-ai@0.1.32
34
+ nsauditor-ai mcp install-key # prints the new snippet — paste into Claude Desktop config
35
+ nsauditor-ai mcp tier # confirm the actual MCP server tier (ground truth)
36
+ ```
37
+
38
+ See [Authentication](#authentication-required-new-in-0131) and [Troubleshooting MCP authentication](#troubleshooting-mcp-authentication) for full setup + diagnostics.
39
+
40
+ ---
41
+
42
+ ## What's New (0.1.31) — security release
43
+
44
+ **MCP server authentication is now required.** Pre-0.1.31, the local MCP server (stdio transport) accepted any incoming JSON-RPC frames — any process running as your user could spawn it and use the Pro/Enterprise tools (which include the AWS-talking shadow-admin path detectors that ship in `@nsasoft/nsauditor-ai-ee@0.3.4`). 0.1.31 closes this gap with a per-operator shared-secret check at startup.
45
+
46
+ **Breaking change for existing operators**: after upgrading, run `nsauditor-ai mcp install-key` once. Without this step, the MCP server refuses to start and Claude Desktop will report a connection failure. The error message points back at this command.
47
+
48
+ ```bash
49
+ npm install -g nsauditor-ai@0.1.31
50
+ nsauditor-ai mcp install-key # generates a 256-bit key, persists it, prints Claude Desktop config snippet
51
+ ```
52
+
53
+ **What's in the box (EE-SEC.1):**
54
+
55
+ - `nsauditor-ai mcp install-key` — generates a 256-bit auth key, stores it in macOS Keychain (or `~/.nsauditor/.env` mode 0600 elsewhere), prints a paste-ready Claude Desktop config snippet. Run once per machine.
56
+ - `nsauditor-ai mcp status` / `print-key --confirm` / `rotate-key --confirm` — inspect, reveal (TTY-only by default), and rotate the key.
57
+ - **`keychain:` indirection on macOS** — the printed config snippet uses `"NSA_MCP_AUTH_KEY": "keychain:NSA_MCP_AUTH_KEY"` instead of the literal key. The MCP server resolves the placeholder at startup; **the secret never lands in your `claude_desktop_config.json`** (which is mode 0644 on macOS by default — readable by other local users and any sandboxed app). On Linux/Windows where there's no Keychain equivalent, the snippet falls back to the literal key with a `chmod 600` warning.
58
+ - **`NSA_MCP_AUTH_DISABLE=1`** escape hatch for CI / dev — emits a stderr warning every startup so you don't forget; a louder warning fires when DISABLE is set AND no key was ever installed.
59
+ - Multi-source resolver mirrors the existing license-key pattern: env → Keychain → file. Constant-time key comparison via `crypto.timingSafeEqual`. Two-reviewer cycle (general code review + network-security-audit lens) caught and folded 2 CRITICAL + 5 MEDIUM findings same-session before commit; full threat model documented in [`utils/mcp_auth.mjs`](./utils/mcp_auth.mjs).
60
+
61
+ See the [MCP Server § Authentication section](#authentication-required-new-in-0131) for the full setup walkthrough, troubleshooting, and the threat-model table.
62
+
63
+ ---
64
+
65
+ ## What's New in Enterprise Edition (0.3.3)
66
+
67
+ The Enterprise Edition (`@nsasoft/nsauditor-ai-ee`) shipped a 0.3.3 point release on 2026-05-08. CE stays at 0.1.30 — no bump required, the EE upgrade is single-line: `npm install -g @nsasoft/nsauditor-ai-ee@latest`. The release closes a Critical false-clean SOC 2 reporting bug that mirrored the AWS-side bug fixed in 0.3.2 — this time in the Azure cloud scanner — and extends mapped SOC 2 coverage to multi-cloud:
68
+
69
+ - **Azure plugin (022) finding-shape rewrite** — the EE-0.3.2.1 cloud-finding harvester only recognized one canonical shape (`{resource, severity, issues[]}`); plugin 022 was emitting `{severity, finding, resource}` (singular `finding`). Findings reached the engine but were silently dropped — Azure customers running `--compliance soc2` saw "6/6 covered controls passing" against subscriptions with real RBAC + NSG + Storage issues. Caught at internal dogfood against a live Azure subscription.
70
+ - **GCP plugin (021) preventive shape port** — plugin 021 had the same `{finding}` singular shape; pre-emptively migrated to the canonical shape so the same bug doesn't re-emerge for GCP customers in v0.4.0 when GCP `mapsToFindings` rules ship.
71
+ - **Azure → SOC 2 mapping rules added** — RBAC `Owner | Contributor | User Access Administrator at subscription scope` → CC6.1 (3 patterns); NSG `0.0.0.0/0 → port` anchored regex → CC6.6; Storage `allowBlobPublicAccess` + `enableHttpsTrafficOnly` → C1.1. CC6.1, CC6.6, and C1.1 now have *both* AWS-side and Azure-side evidence rows — actual multi-cloud SOC 2 evidence.
72
+ - **Drift detector extended to all three cloud plugins** — every `azure-cloud-scanner` `titlePattern` in `soc2.json` is now asserted to match at least one canonical issue string the plugin emits, and vice versa. The class-of-bug that produced two false-clean variants in successive releases is now structurally closed.
73
+ - **Pre-publish gate fixes** — `@azure/arm-authorization` peer-dep was pinned at `^10.0.0` (latest published is 9.0.0; clean installs would have failed); `@azure/arm-storage` was missing from `optionalDependencies` (Storage audit silently no-op'd on clean install). Both caught at the pre-publish clean-tarball smoke and corrected before ship.
74
+
75
+ See [EE README](https://www.npmjs.com/package/@nsasoft/nsauditor-ai-ee) for the full 0.3.3 changelog and Azure scan walkthrough.
76
+
77
+ ---
78
+
18
79
  ## What's New (0.1.30)
19
80
 
20
81
  The 0.1.30 line is a paired release with `@nsasoft/nsauditor-ai-ee@0.3.2` that closes the customer-onboarding gap and a critical false-clean SOC 2 reporting bug:
@@ -60,7 +121,7 @@ NSAuditor AI is available in three editions:
60
121
  | Advanced CTEM + trend analysis | — | ✅ | ✅ |
61
122
  | Cloud scanners (AWS/GCP/Azure) | — | — | ✅ |
62
123
  | Zero Trust assessment | — | — | ✅ |
63
- | SOC 2 compliance (8 covered + 5 partial controls) | — | — | ✅ |
124
+ | SOC 2 compliance (8 covered + 5 partial controls; AWS + Azure evidence streams) | — | — | ✅ |
64
125
  | SLA/MTTR tracking + compensating controls | — | — | ✅ |
65
126
  | Recurring-scan attestation (Type II evidence) | — | — | ✅ |
66
127
  | GRC platform connector (Vanta) | — | — | ✅ |
@@ -182,7 +243,7 @@ Results land in `./out/<host>_<timestamp>/`:
182
243
  |---|---|---|---|
183
244
  | 020 | AWS Cloud Scanner | Enterprise | Security group + IAM policy analysis |
184
245
  | 021 | GCP Cloud Scanner | Enterprise | Firewall rules + IAM bindings |
185
- | 022 | Azure Cloud Scanner | Enterprise | NSG rules + RBAC analysis |
246
+ | 022 | Azure Cloud Scanner | Enterprise | NSG rules + RBAC role assignments + Storage account hardening; SOC 2 mapping (CC6.1, CC6.6, C1.1) shipped in EE 0.3.3 |
186
247
  | 023 | Zero Trust Checker | Enterprise | Segmentation, encryption, identity, lateral movement scoring |
187
248
  | — | SOC 2 Compliance Engine | Enterprise | AICPA TSC 2017 control mapping, chain-of-custody, RFC 3161 timestamps, suppression workflow |
188
249
  | — | SLA & MTTR Tracking | Enterprise | Per-severity SLA targets, compensating-control flow, finding lifecycle |
@@ -292,7 +353,56 @@ npx nsauditor-ai-mcp
292
353
  | `compliance_check` | Compliance mapping with gap analysis |
293
354
  | `export_report` | Generate formatted compliance report |
294
355
 
295
- Security: SSRF protection on all host inputs (blocks RFC 1918, loopback, fc00::/7, cloud metadata), port validation (1–65535), CPE format enforcement, dependency injection for test isolation.
356
+ Security: SSRF protection on all host inputs (blocks RFC 1918, loopback, fc00::/7, cloud metadata), port validation (1–65535), CPE format enforcement, dependency injection for test isolation. **Server-startup authentication required as of 0.1.31** — see next section.
357
+
358
+ ### Authentication (required, NEW in 0.1.31)
359
+
360
+ The MCP server uses stdio transport, which means it runs as a child process of whatever client launches it. Without authentication, **any process running as your user could spawn the server and use its tools** — including the Pro/Enterprise tools that talk to AWS, generate compliance reports, and access your scan history. 0.1.31 closes this gap with a per-operator shared-secret check at server startup.
361
+
362
+ **One-time setup** (run once per machine after `npm install -g nsauditor-ai`):
363
+
364
+ ```bash
365
+ nsauditor-ai mcp install-key
366
+ ```
367
+
368
+ This generates a 256-bit auth key, stores it in the macOS Keychain (or `~/.nsauditor/.env` mode 0600 on Linux/Windows), and prints the Claude Desktop config snippet for you to paste. **The MCP server refuses to start unless the env-presented key matches the stored key** (constant-time compare; mismatch produces an actionable error pointing at this command).
369
+
370
+ **Inspect / verify**:
371
+
372
+ ```bash
373
+ nsauditor-ai mcp status # shows storage source WITHOUT printing the key
374
+ nsauditor-ai mcp print-key --confirm # reveals the key (use sparingly; refuses non-TTY output)
375
+ nsauditor-ai mcp rotate-key --confirm # generates a new key (invalidates old one immediately)
376
+ ```
377
+
378
+ **Why the Claude Desktop config snippet uses `keychain:` indirection on macOS**: the printed snippet looks like `"NSA_MCP_AUTH_KEY": "keychain:NSA_MCP_AUTH_KEY"` rather than the literal key value. The MCP server resolves the placeholder from your Keychain at startup. Net effect: **the secret never lands in `~/Library/Application Support/Claude/claude_desktop_config.json`** (which is mode 0644 by default — readable by other local users and any macOS app with Documents/Application Support entitlement). On Linux/Windows where there's no Keychain equivalent, the snippet uses the literal key with an explicit `chmod 600` warning.
379
+
380
+ **Threat model — what this defends, what it doesn't**:
381
+
382
+ | Threat | Defended? |
383
+ |---|---|
384
+ | Malicious npm post-install / browser extension running as you spawning the server | ✅ — attacker cannot read your Keychain without GUI prompt |
385
+ | Other users on a shared dev box / CI runner | ✅ — key is per-operator |
386
+ | Future HTTP/SSE transport network exposure | ✅ — key gates server startup, not network |
387
+ | Attacker with full operator code-exec AND can suppress macOS Keychain prompts | ⚠ partial — recent macOS versions log Keychain-access denial events |
388
+ | Debugger-attach memory snooping | ⚠ out of scope (any shared-secret auth has this limit) |
389
+ | Linux env-var visibility in `/proc/<pid>/environ` | ⚠ partial — see Linux note below |
390
+
391
+ **Linux note (`/proc/<pid>/environ`)**: on modern Linux, `/proc/<pid>/environ` is readable only by the process owner (the same user that spawned the MCP server). Other users on a multi-user system **cannot** read your MCP auth key from `/proc` under default kernel settings. The realistic remaining risks are:
392
+
393
+ - Container scenarios where multiple "users" share the same kernel UID (e.g., a Docker container running as root, with multiple processes inside) — the secret is visible to any process in the same UID namespace. Mitigation: run the MCP server in its own container / user.
394
+ - Audit/SIEM agents with broad read access (e.g., `auditd` configured to log child-process env). Mitigation: review your `auditd` rules; modern setups exclude env from logs by default.
395
+ - The legacy `ps eww` command on older POSIX systems (modern `ps` respects `/proc` permissions).
396
+
397
+ A shell-wrapper indirection script (read key from `~/.nsauditor/.env` at exec time, pass to child) was considered for v1 but does NOT solve the underlying issue: the spawned MCP server still needs the key in its env to perform the auth check, so it appears in `/proc/<server-pid>/environ` regardless of how the parent process obtained it. v2 may add libsecret integration on Linux to mirror the macOS Keychain indirection model.
398
+
399
+ **Rotation cadence (NEW in 0.1.32)**: keys older than 90 days emit a soft warning at every server startup AND in `nsauditor-ai mcp status` output. SOC 2 CC6.1 / CC6.7 reviewers expect a credential-rotation cadence; rotate with `nsauditor-ai mcp rotate-key --confirm` and update Claude Desktop config with the new key.
400
+
401
+ **Escape hatch for CI / dev** (operator-acknowledged risk; emits a stderr warning every startup):
402
+
403
+ ```bash
404
+ NSA_MCP_AUTH_DISABLE=1 nsauditor-ai-mcp
405
+ ```
296
406
 
297
407
  ### Claude Desktop Setup
298
408
 
@@ -300,6 +410,7 @@ First install the package globally:
300
410
 
301
411
  ```bash
302
412
  npm install -g nsauditor-ai
413
+ nsauditor-ai mcp install-key # NEW in 0.1.31 — required before MCP server will start
303
414
  ```
304
415
 
305
416
  Then add this to your `claude_desktop_config.json` (Settings → Developer → Edit Config):
@@ -308,11 +419,11 @@ Then add this to your `claude_desktop_config.json` (Settings → Developer → E
308
419
  {
309
420
  "mcpServers": {
310
421
  "nsauditor-ai": {
311
- "command": "node",
312
- "args": ["/path/to/global/node_modules/nsauditor-ai/mcp_server.mjs"],
422
+ "command": "nsauditor-ai-mcp",
313
423
  "env": {
424
+ "NSA_MCP_AUTH_KEY": "keychain:NSA_MCP_AUTH_KEY",
314
425
  "AI_PROVIDER": "claude",
315
- "ANTHROPIC_API_KEY": "your-key-here",
426
+ "ANTHROPIC_API_KEY": "keychain:ANTHROPIC_API_KEY",
316
427
  "NSA_ALLOW_ALL_HOSTS": "1",
317
428
  "PLUGIN_TIMEOUT_MS": "5000"
318
429
  }
@@ -321,8 +432,9 @@ Then add this to your `claude_desktop_config.json` (Settings → Developer → E
321
432
  }
322
433
  ```
323
434
 
324
- Find your global install path with `npm root -g`, then append `/nsauditor-ai/mcp_server.mjs`.
435
+ The exact `NSA_MCP_AUTH_KEY` value to paste is printed by `nsauditor-ai mcp install-key` on macOS it's the `keychain:NSA_MCP_AUTH_KEY` placeholder shown above; on Linux/Windows it's the literal key value (and you should `chmod 600` your config file).
325
436
 
437
+ - `NSA_MCP_AUTH_KEY` — **required as of 0.1.31** (see Authentication section above)
326
438
  - `NSA_ALLOW_ALL_HOSTS=1` — required to scan private/RFC 1918 addresses (e.g., `192.168.x.x`)
327
439
  - `PLUGIN_TIMEOUT_MS=5000` — reduces per-plugin timeout to 5s so the full scan completes within Claude Desktop's 60s MCP limit
328
440
  - `AI_PROVIDER` and API key — optional, enables AI-powered analysis of scan results
@@ -330,9 +442,47 @@ Find your global install path with `npm root -g`, then append `/nsauditor-ai/mcp
330
442
  ### Claude Code Setup
331
443
 
332
444
  ```bash
333
- claude mcp add nsauditor-ai -- npx nsauditor-ai-mcp
445
+ nsauditor-ai mcp install-key # NEW in 0.1.31 — required before MCP server will start
446
+ claude mcp add nsauditor-ai \
447
+ --env NSA_MCP_AUTH_KEY=keychain:NSA_MCP_AUTH_KEY \
448
+ -- npx nsauditor-ai-mcp
334
449
  ```
335
450
 
451
+ (On Linux/Windows, replace the `keychain:NSA_MCP_AUTH_KEY` placeholder with the literal key printed by `install-key`.)
452
+
453
+ ### Troubleshooting MCP authentication
454
+
455
+ **"MCP authentication is not configured"** at server startup → run `nsauditor-ai mcp install-key`. If you set `NSA_MCP_AUTH_DISABLE=1` in CI by intent, that's fine — but check that you didn't forget it in your shell rc.
456
+
457
+ **"NSA_MCP_AUTH_KEY env var is not set, but a key is configured in storage"** → the server found a key in your Keychain (or `~/.nsauditor/.env`) but the spawning client didn't pass `NSA_MCP_AUTH_KEY` in the env block. Update your Claude Desktop / Claude Code config to include the env value (use `nsauditor-ai mcp install-key` output as a reference snippet).
458
+
459
+ **"NSA_MCP_AUTH_KEY env var does not match the key configured in storage"** → most often means you ran `nsauditor-ai mcp rotate-key --confirm` but didn't update Claude Desktop config with the new key. Run `nsauditor-ai mcp status` to confirm storage source, then either re-paste the new key or use `keychain:NSA_MCP_AUTH_KEY` indirection (macOS only) so future rotations don't require a config change.
460
+
461
+ **"MCP_AUTH uses keychain: indirection but the referenced Keychain entry could not be read"** → typically a headless macOS / SSH-only CI runner where there's no GUI session to approve Keychain access. Replace the `keychain:` placeholder with the literal key value (or move auth to `~/.nsauditor/.env` with mode 0600).
462
+
463
+ **`mcp status` reports `keychain-locked`** (NEW in 0.1.32) → distinct from `unconfigured`: the Keychain entry exists but the security daemon refused to unlock without a GUI prompt. Same workarounds as the previous error: approve a Keychain GUI prompt, replace `keychain:` indirection with the literal key, or move auth to `~/.nsauditor/.env`. Pre-0.1.32 the resolver silently fell through to the file branch and reported `unconfigured` — the new state distinguishes "operator never ran install-key" from "operator did run it but Keychain is locked right now".
464
+
465
+ **`mcp status` shows `⚠ Created: ... — > 90d threshold`** (NEW in 0.1.32) → key is older than the 90-day rotation cadence. Run `nsauditor-ai mcp rotate-key --confirm` and update Claude Desktop config with the new key. Server emits the same warning to stderr at every startup.
466
+
467
+ **Claude Desktop reports "Current tier: CE" despite `nsauditor-ai license --status` showing Enterprise** (NEW in 0.1.32) → first run `nsauditor-ai mcp tier` to get the **ground-truth tier** the MCP server actually resolves at startup. If `mcp tier` reports `enterprise` but Claude Desktop's `list_plugins` says CE, **Claude (the AI) is synthesizing the tier text from context rather than calling the tool**. Force a real call by asking in a NEW Claude Desktop conversation:
468
+
469
+ > Use the `list_plugins` MCP tool right now and show me the raw tool response verbatim, including the exact text after the JSON.
470
+
471
+ Then check the MCP log to verify a real call happened:
472
+
473
+ ```bash
474
+ grep '"method":"tools/call"' ~/Library/Logs/Claude/mcp-server-nsauditor-ai.log | tail -5
475
+ ```
476
+
477
+ If `mcp tier` itself reports CE → genuine resolution failure. Inspect the license storage:
478
+
479
+ ```bash
480
+ nsauditor-ai license --status
481
+ security find-generic-password -s nsauditor-ai -a NSAUDITOR_LICENSE_KEY -w 2>&1 | head -c 30
482
+ ```
483
+
484
+ If license is in `~/.nsauditor/.env` but not in Keychain on macOS, re-run `nsauditor-ai mcp install-key` — the auto-mirror writes the license to Keychain so Claude Desktop's child process can read it via the `keychain:` indirection.
485
+
336
486
  ---
337
487
 
338
488
  ## Secure Credential Storage