nsauditor-ai 0.1.36 → 0.1.38

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
@@ -7,204 +7,22 @@ A modular, AI-assisted network security audit platform that scans, understands,
7
7
  [![npm](https://img.shields.io/npm/v/nsauditor-ai.svg)](https://www.npmjs.com/package/nsauditor-ai)
8
8
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
9
  [![Node.js 20+](https://img.shields.io/badge/node-20%2B-green.svg)](https://nodejs.org)
10
- [![Tests](https://img.shields.io/badge/tests-506%20passing-brightgreen.svg)](#tests)
10
+ [![Tests](https://img.shields.io/badge/tests-925%20passing-brightgreen.svg)](#tests)
11
11
 
12
12
  ---
13
13
 
14
- NSAuditor AI is the open-source core of a privacy-first security intelligence platform built by [Nsasoft US LLC](https://www.nsauditor.com/ai/). It orchestrates 20+ specialized scanning plugins against target hosts, fuses their results through an intelligent concluder, and optionally produces AI-powered vulnerability reports — all running entirely on your machine.
14
+ NSAuditor AI is the open-source core of a privacy-first security intelligence platform built by [Nsasoft US LLC](https://www.nsauditor.com/ai/). It orchestrates 27 specialized scanning plugins against target hosts, fuses their results through an intelligent concluder, and optionally produces AI-powered vulnerability reports — all running entirely on your machine.
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.36) — cryptographic per-call sentinel UUID (hallucination becomes mathematically detectable)
18
+ ## What's New
19
19
 
20
- The version-block comparison shipped in 0.1.34/0.1.35 catches lazy hallucinations, but a sufficiently capable AI client can still copy a previously-seen version block from chat context and pass off a fabricated response. **0.1.36 closes that gap** with a per-call cryptographic sentinel that the AI cannot fake.
21
-
22
- **How it works:**
23
- - Each `tools/call` invocation mints a fresh server-side UUID via Node's `crypto.randomUUID()`.
24
- - The UUID is appended to the response text under a `── Verified MCP call ──` footer.
25
- - The same UUID is persisted to `~/.nsauditor/mcp-calls.log` (mode 0600, JSON-per-line) **before** the response is returned.
26
- - A new CLI subcommand `nsauditor-ai mcp verify-call <uuid>` greps the log:
27
- - **Found** → the UUID was issued by your local MCP server, so the response bearing it is genuine.
28
- - **Not found** → the UUID was never issued, so the entire response was fabricated by the AI client.
29
-
30
- **Customer verification workflow (10 seconds):**
31
-
32
- ```bash
33
- # 1. In Claude Desktop, ask Claude to use any MCP tool (e.g., list_plugins).
34
- # 2. The response ends with:
35
- # ── Verified MCP call ──
36
- # call_id: 3f8a1b22-7e44-4c91-9d62-12bd0a4f5e91
37
- # Verify: nsauditor-ai mcp verify-call 3f8a1b22-7e44-4c91-9d62-12bd0a4f5e91
38
- # 3. Run that exact verify command in your terminal:
39
- nsauditor-ai mcp verify-call 3f8a1b22-7e44-4c91-9d62-12bd0a4f5e91
40
- # ✓ Verified MCP call → genuine
41
- # ✗ call_id not found → fabricated (response was AI-generated, not from the MCP server)
42
- ```
43
-
44
- This makes the hallucination detection unfakeable in principle: the AI client has no access to your local Node `crypto.randomUUID()` output, and the sentinel is generated **at the moment the call hits the server** — there's no way to forge a UUID that will appear in a log file the client cannot read or write.
45
-
46
- The 0.1.34/0.1.35 version-block check remains as the first line of defense (instant visual mismatch). The 0.1.36 UUID is the cryptographic ground truth for any response you'd act on.
47
-
48
- `scan_host`, `probe_service`, `get_vulnerabilities`, and `list_plugins` all mint sentinels — even Pro-tier denials carry a UUID so customers can prove the call reached the server.
49
-
50
- ```bash
51
- npm install -g nsauditor-ai@0.1.36
52
- ```
53
-
54
- ---
55
-
56
- ## What's New (0.1.35) — CLI provenance footer matches MCP response (so the comparison actually works)
57
-
58
- 0.1.34 added the version-provenance block to the MCP server's `list_plugins` response, but **the CLI baseline (`license --plugins` / `license --status`) didn't show versions** — so customers couldn't easily compare. 0.1.35 fixes that asymmetry.
59
-
60
- Both CLI commands now emit an identical provenance block:
61
-
62
- ```
63
- ── Installation provenance ──
64
- nsauditor-ai (CE): 0.1.35
65
- @nsasoft/nsauditor-ai-ee (EE): 0.3.4 (loaded)
66
- ```
67
-
68
- **Customer hallucination-detection workflow (5 seconds, no log archeology):**
69
-
70
- 1. In Claude Desktop: ask "list plugins" → receive a response that should end with the provenance block
71
- 2. In your terminal: run `nsauditor-ai license --plugins`
72
- 3. Compare the two `── Installation provenance ──` blocks character-for-character
73
- 4. **Match** → real MCP `tools/call` happened, response is trustworthy
74
- 5. **Mismatch / missing block** → Claude fabricated the response (see CE 0.1.33 advisory)
75
-
76
- This is the v1 mitigation; the v2 (Thread L Phase 2) adds per-call cryptographic sentinel UUIDs that the customer can grep against the server log directly. v1 catches the common case where Claude either omits the block entirely (unlikely to fabricate the new structure verbatim) or includes a stale version pulled from training data.
77
-
78
- ---
79
-
80
- ## What's New (0.1.34) — list_plugins now embeds CE+EE versions for hallucination detection
81
-
82
- Companion to the 0.1.33 advisory. The `list_plugins` MCP tool's response now appends the actual installed CE + EE version numbers, so customers can verify a Claude Desktop response in **5 seconds** without log archeology:
83
-
84
- ```
85
- ── Installation provenance (verify against your shell) ──
86
- nsauditor-ai (CE): 0.1.34
87
- @nsasoft/nsauditor-ai-ee (EE): 0.3.4 (loaded)
88
- Verify: nsauditor-ai --version && npm list -g @nsasoft/nsauditor-ai-ee
89
- If versions in this response don't match your shell, the response was
90
- AI-generated rather than retrieved from the MCP server (see CE 0.1.33 advisory).
91
- ```
92
-
93
- How it works as a hallucination detector:
94
- - The MCP server reads `process.execPath`'s package.json + tries to resolve `@nsasoft/nsauditor-ai-ee/package.json` at request time. Both are real machine-specific values.
95
- - Claude Desktop fabricated responses in the wild have shown stale version numbers from training data, missing version lines entirely, or different counts each time the same question is asked (observed 32→32→31 plugin counts in three consecutive hallucinations on 2026-05-10).
96
- - A real tool response will exactly match `nsauditor-ai --version` + `npm list -g @nsasoft/nsauditor-ai-ee`. Mismatch = hallucinated.
97
-
98
- This is a v1 mitigation — the v2 (Thread L in `tasks/todo.md`) adds per-call cryptographic sentinel UUIDs that the customer can grep against the server log.
99
-
100
- ---
101
-
102
- ## What's New (0.1.33) — ⚠ MCP integration with Claude Desktop is unreliable
103
-
104
- **Critical advisory for customers using NSAuditor AI through Claude Desktop's MCP integration.** During the maintainer's own integration test on 2026-05-10, we discovered that **Claude Desktop's AI fabricates scan results, plugin lists, vulnerability findings, and tier information without actually invoking the MCP tools** for our specific server. Other MCP servers in the same Claude Desktop config receive real `tools/call` invocations; ours does not.
105
-
106
- **Empirical evidence**:
107
- - `~/Library/Logs/Claude/main.log` shows multiple permission grants for `mcp__nsauditor-ai__list_plugins` and `mcp__nsauditor-ai__scan_host` on 2026-05-10
108
- - `~/Library/Logs/Claude/mcp-server-nsauditor-ai.log` shows **zero** `"method":"tools/call"` entries on the same day
109
- - Other servers in the same config logged real calls (ns-ftp:29, wp-publisher-netsecmag:14, ai-pr-distribution:6, sendgrid:3)
110
- - When asked to scan 1.1.1.1, Claude Desktop returned a detailed report with plugin breakdown + Zero Trust score — entirely fabricated
111
-
112
- **Likely cause**: Claude Desktop's MCP client appears to time out our server (which loads PluginManager + 32 plugins + license verify before responding). Claude (the AI) silently substitutes fabricated responses from training rather than surfacing the timeout. The hallucinations are convincingly formatted and indistinguishable from real output without log inspection.
113
-
114
- **Mandatory verification — for any output you'd act on**:
115
-
116
- ```bash
117
- # Tier check (ground truth bypassing Claude AI synthesis):
118
- nsauditor-ai mcp tier
119
-
120
- # Real plugin scan (always hits the network):
121
- nsauditor-ai scan --host <X> --plugins all --out <dir>
122
-
123
- # Confirm Claude Desktop actually called the MCP server:
124
- grep '"method":"tools/call"' ~/Library/Logs/Claude/mcp-server-nsauditor-ai.log | tail -5
125
- # If main.log shows recent permission grants for nsauditor-ai tools but
126
- # THIS file shows no matching tools/call entries, the responses you saw
127
- # in Claude Desktop were AI-generated, NOT real.
128
- ```
129
-
130
- **SOC 2 evidence and any compliance report MUST be generated via the CLI** — never via the Claude Desktop MCP integration — until this is resolved upstream. We're working on it (Thread L in `tasks/todo.md`): a per-call cryptographic sentinel, lazy-loaded plugin discovery to reduce startup latency, a `mcp verify-recent-call` diagnostic, and a bug report to Anthropic.
131
-
132
- This advisory will be removed when the upstream Claude Desktop MCP routing issue is fixed and we ship a CE release whose `tools/call` invocations land reliably.
133
-
134
- ---
135
-
136
- ## What's New (0.1.32) — Claude Desktop integration overhaul + ground-truth diagnostics
137
-
138
- 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):
139
-
140
- - **`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.
141
- - **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.
142
- - **`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."
143
- - **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.
144
- - **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.
145
- - **Atomic file writes** for `~/.nsauditor/.env` (`.tmp` + POSIX-rename) so concurrent readers + crash recovery never observe a truncated file.
146
- - **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.
147
-
148
- **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.
149
-
150
- ```bash
151
- npm install -g nsauditor-ai@0.1.32
152
- nsauditor-ai mcp install-key # prints the new snippet — paste into Claude Desktop config
153
- nsauditor-ai mcp tier # confirm the actual MCP server tier (ground truth)
154
- ```
155
-
156
- See [Authentication](#authentication-required-new-in-0131) and [Troubleshooting MCP authentication](#troubleshooting-mcp-authentication) for full setup + diagnostics.
157
-
158
- ---
159
-
160
- ## What's New (0.1.31) — security release
161
-
162
- **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.
163
-
164
- **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.
165
-
166
- ```bash
167
- npm install -g nsauditor-ai@0.1.31
168
- nsauditor-ai mcp install-key # generates a 256-bit key, persists it, prints Claude Desktop config snippet
169
- ```
170
-
171
- **What's in the box (EE-SEC.1):**
172
-
173
- - `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.
174
- - `nsauditor-ai mcp status` / `print-key --confirm` / `rotate-key --confirm` — inspect, reveal (TTY-only by default), and rotate the key.
175
- - **`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.
176
- - **`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.
177
- - 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).
178
-
179
- See the [MCP Server § Authentication section](#authentication-required-new-in-0131) for the full setup walkthrough, troubleshooting, and the threat-model table.
20
+ - **0.1.38 (current)** docs-only. README rewritten to be feature-and-usage focused; release history moved to [CHANGELOG.md](./CHANGELOG.md); new [docs/mcp-verification.md](./docs/mcp-verification.md) for the `nsauditor-ai mcp verify-call` workflow. No functional change vs 0.1.37.
21
+ - **0.1.37 — 🛑 security fix**, upgrade if you're on anything earlier. The MCP bin shim (`nsauditor-ai-mcp`) was bypassing both `NSA_MCP_AUTH_KEY` enforcement and license verification on every spawn. Defense-in-depth degradation, plus paid Pro/Enterprise customers were stuck at CE tier through MCP. `npm install -g nsauditor-ai@latest` + restart your MCP client.
22
+ - **Authenticated MCP server, Keychain-backed secrets, per-call sentinel UUIDs, multi-source license loader, `--version` / `validate` / `license install` subcommands.** All shipped across 0.1.30 → 0.1.37 — see [CHANGELOG.md](./CHANGELOG.md) for the per-release detail.
180
23
 
181
24
  ---
182
25
 
183
- ## What's New in Enterprise Edition (0.3.3)
184
-
185
- 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:
186
-
187
- - **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.
188
- - **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.
189
- - **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.
190
- - **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.
191
- - **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.
192
-
193
- See [EE README](https://www.npmjs.com/package/@nsasoft/nsauditor-ai-ee) for the full 0.3.3 changelog and Azure scan walkthrough.
194
-
195
- ---
196
-
197
- ## What's New (0.1.30)
198
-
199
- 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:
200
-
201
- - **`nsauditor-ai license install <KEY>`** — verifies the JWT *before* persisting; writes to macOS Keychain or `~/.nsauditor/.env` (mode 0600) depending on platform. Three-line install flow: `npm install -g` → `license install` → `license --status`. No more shell-rc edits.
202
- - **Multi-source license loader** — `loadLicense()` resolves keys from env var → platform Keychain → `~/.nsauditor/.env`, in that order. CI/CD env-var override still wins.
203
- - **`nsauditor-ai license --plugins`** — real enumeration of discovered plugins, grouped by source (CE / EE / custom), with active-or-required-tier status.
204
- - **`nsauditor-ai --version` / `-v`** — prints version and exits 0 (parallel to `--help`'s discovery-flag UX).
205
- - **Cloud-sentinel SSRF bypass** — `--host aws|gcp|azure` no longer requires `NSA_ALLOW_ALL_HOSTS=1`. The sentinel literals route to EE cloud-scanner plugins via the provider's API; the SSRF guard's RFC 1918 / loopback protection is preserved for real network targets.
206
- - **EE-0.3.2.1 hard dep** — CE forwards the per-plugin `results` array to `enrichScan()`. Without this, EE 0.3.2's cloud-finding harvester sees nothing and produces false-clean SOC 2 reports against AWS accounts. EE emits a runtime version-skew warning when this opt is missing.
207
-
208
26
  ## What It Does
209
27
 
210
28
  ```
@@ -359,10 +177,11 @@ Results land in `./out/<host>_<timestamp>/`:
359
177
 
360
178
  | ID | Name | Tier | Purpose |
361
179
  |---|---|---|---|
362
- | 020 | AWS Cloud Scanner | Enterprise | Security group + IAM policy analysis |
180
+ | 020 | AWS Cloud Scanner | Enterprise | S3 bucket hardening, security group + IAM policy analysis with SOC 2 evidence mapping |
363
181
  | 021 | GCP Cloud Scanner | Enterprise | Firewall rules + IAM bindings |
364
- | 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 |
182
+ | 022 | Azure Cloud Scanner | Enterprise | NSG rules + RBAC role assignments + Storage account hardening, SOC 2 evidence mapping (CC6.1 / CC6.6 / C1.1) |
365
183
  | 023 | Zero Trust Checker | Enterprise | Segmentation, encryption, identity, lateral movement scoring |
184
+ | 030 | AWS IAM Deep Auditor | Enterprise | Shadow-admin path detection via BFS over PassRole / AssumeRole / federated trust; per-finding remediation pointers; SOC 2 CC6.1 evidence |
366
185
  | — | SOC 2 Compliance Engine | Enterprise | AICPA TSC 2017 control mapping, chain-of-custody, RFC 3161 timestamps, suppression workflow |
367
186
  | — | SLA & MTTR Tracking | Enterprise | Per-severity SLA targets, compensating-control flow, finding lifecycle |
368
187
  | — | Recurring-Scan Attestation | Enterprise | Multi-scan chronological matrix, cadence gap detection, scope drift (CC8.1) |
@@ -437,27 +256,7 @@ nsauditor-ai scan --host 192.168.1.0/24 --plugins all \
437
256
 
438
257
  ## MCP Server
439
258
 
440
- > ## CRITICAL ADVISORY (2026-05-10) Claude Desktop hallucinates responses for this MCP server
441
- >
442
- > When you use NSAuditor AI through **Claude Desktop's** MCP integration, the AI may **fabricate scan results, plugin lists, vulnerability findings, and tier information without actually invoking the MCP tools**. We've confirmed this empirically: Claude Desktop's permission system shows tool calls being approved, but the actual `tools/call` JSON-RPC messages never reach our server (other MCP servers in the same config receive their calls correctly).
443
- >
444
- > **Mandatory verification for any output you'd act on (NEW in 0.1.36 — works for any MCP client):**
445
- >
446
- > ```bash
447
- > # Cryptographic ground truth: copy the call_id from the response footer
448
- > # ("── Verified MCP call ──") and run:
449
- > nsauditor-ai mcp verify-call <call_id>
450
- > # ✓ Verified MCP call → genuine, response is trustworthy
451
- > # ✗ call_id not found → fabricated, IGNORE the response
452
- >
453
- > # Real tier check (bypasses Claude AI synthesis):
454
- > nsauditor-ai mcp tier
455
- >
456
- > # Real scan (always hits the network, no MCP client involved):
457
- > nsauditor-ai scan --host <X> --plugins all --out <dir>
458
- > ```
459
- >
460
- > **SOC 2 evidence + compliance reports MUST be generated via the CLI** — never via the Claude Desktop MCP integration — unless every response you act on has a verified call_id. Other MCP clients (Claude Code, custom MCP clients via the SDK) appear unaffected. See [What's New (0.1.36)](#whats-new-0136--cryptographic-per-call-sentinel-uuid-hallucination-becomes-mathematically-detectable) for the cryptographic mitigation and [What's New (0.1.33)](#whats-new-0133----mcp-integration-with-claude-desktop-is-unreliable) for the original advisory.
259
+ > **Heads-up on AI-client fabrication.** Some MCP clients (notably Claude Desktop) can silently substitute AI-generated responses if a `tools/call` times out, instead of surfacing the failure. Every response from this server now ends with a `── Verified MCP call ──` footer and a UUID. Run `nsauditor-ai mcp verify-call <id>` to confirm a response is genuine before acting on it. Full background and workflow: [docs/mcp-verification.md](./docs/mcp-verification.md). When in doubt, generate compliance evidence via the CLI (`nsauditor-ai scan ...`), which has no MCP client in the path.
461
260
 
462
261
  Expose scanning capabilities to AI assistants via [Model Context Protocol](https://modelcontextprotocol.io):
463
262
 
@@ -493,11 +292,11 @@ npx nsauditor-ai-mcp
493
292
  | `compliance_check` | Compliance mapping with gap analysis |
494
293
  | `export_report` | Generate formatted compliance report |
495
294
 
496
- 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.
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. **Server-startup authentication is required** — see next section.
497
296
 
498
- ### Authentication (required, NEW in 0.1.31)
297
+ ### Authentication (required)
499
298
 
500
- 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.
299
+ 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. A per-operator shared-secret check at server startup closes this gap.
501
300
 
502
301
  **One-time setup** (run once per machine after `npm install -g nsauditor-ai`):
503
302
 
@@ -536,7 +335,7 @@ nsauditor-ai mcp rotate-key --confirm # generates a new key (invalidates old
536
335
 
537
336
  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.
538
337
 
539
- **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.
338
+ **Rotation cadence**: 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.
540
339
 
541
340
  **Escape hatch for CI / dev** (operator-acknowledged risk; emits a stderr warning every startup):
542
341
 
@@ -550,7 +349,7 @@ First install the package globally:
550
349
 
551
350
  ```bash
552
351
  npm install -g nsauditor-ai
553
- nsauditor-ai mcp install-key # NEW in 0.1.31 — required before MCP server will start
352
+ nsauditor-ai mcp install-key # required before MCP server will start
554
353
  ```
555
354
 
556
355
  Then add this to your `claude_desktop_config.json` (Settings → Developer → Edit Config):
@@ -574,7 +373,7 @@ Then add this to your `claude_desktop_config.json` (Settings → Developer → E
574
373
 
575
374
  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).
576
375
 
577
- - `NSA_MCP_AUTH_KEY` — **required as of 0.1.31** (see Authentication section above)
376
+ - `NSA_MCP_AUTH_KEY` — **required** (see Authentication section above)
578
377
  - `NSA_ALLOW_ALL_HOSTS=1` — required to scan private/RFC 1918 addresses (e.g., `192.168.x.x`)
579
378
  - `PLUGIN_TIMEOUT_MS=5000` — reduces per-plugin timeout to 5s so the full scan completes within Claude Desktop's 60s MCP limit
580
379
  - `AI_PROVIDER` and API key — optional, enables AI-powered analysis of scan results
@@ -582,7 +381,7 @@ The exact `NSA_MCP_AUTH_KEY` value to paste is printed by `nsauditor-ai mcp inst
582
381
  ### Claude Code Setup
583
382
 
584
383
  ```bash
585
- nsauditor-ai mcp install-key # NEW in 0.1.31 — required before MCP server will start
384
+ nsauditor-ai mcp install-key # required before MCP server will start
586
385
  claude mcp add nsauditor-ai \
587
386
  --env NSA_MCP_AUTH_KEY=keychain:NSA_MCP_AUTH_KEY \
588
387
  -- npx nsauditor-ai-mcp
@@ -600,28 +399,11 @@ claude mcp add nsauditor-ai \
600
399
 
601
400
  **"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).
602
401
 
603
- **`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".
604
-
605
- **`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.
606
-
607
- **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:
608
-
609
- > Use the `list_plugins` MCP tool right now and show me the raw tool response verbatim, including the exact text after the JSON.
610
-
611
- Then verify a real call happened. The 0.1.36+ way (works for any client, not just Claude Desktop):
402
+ **`mcp status` reports `keychain-locked`** → 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`.
612
403
 
613
- ```bash
614
- # Copy the call_id from the response footer that Claude returned, then:
615
- nsauditor-ai mcp verify-call <call_id>
616
- # ✓ Verified MCP call → genuine, response is trustworthy
617
- # ✗ call_id not found → fabricated, IGNORE the response
618
- ```
619
-
620
- The pre-0.1.36 fallback (Claude Desktop log archeology):
404
+ **`mcp status` shows `⚠ Created: ... — > 90d threshold`** → 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.
621
405
 
622
- ```bash
623
- grep '"method":"tools/call"' ~/Library/Logs/Claude/mcp-server-nsauditor-ai.log | tail -5
624
- ```
406
+ **Claude Desktop reports "Current tier: CE" despite `nsauditor-ai license --status` showing Enterprise** → 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, the AI client is synthesizing the response without actually calling the tool — see [docs/mcp-verification.md](./docs/mcp-verification.md) and verify any suspicious response with `nsauditor-ai mcp verify-call <id>`.
625
407
 
626
408
  If `mcp tier` itself reports CE → genuine resolution failure. Inspect the license storage:
627
409
 
@@ -678,7 +460,7 @@ nsauditor-ai --help (or -h, or `help`)
678
460
  nsauditor-ai --version (or -v, or `version`)
679
461
  ```
680
462
 
681
- > Run `nsauditor-ai --help` (or `-h`, or just `nsauditor-ai help`) for a quick reference of subcommands, flags, env vars, and worked examples — works without a license key configured. `--version` / `-v` (CE 0.1.30+) prints `nsauditor-ai <version>` and exits 0.
463
+ > Run `nsauditor-ai --help` (or `-h`, or just `nsauditor-ai help`) for a quick reference of subcommands, flags, env vars, and worked examples — works without a license key configured. `--version` / `-v` prints `nsauditor-ai <version>` and exits 0.
682
464
 
683
465
  | Flag | Description | Default |
684
466
  |---|---|---|
@@ -698,7 +480,7 @@ nsauditor-ai --version (or -v, or `version`)
698
480
  | `--compliance <fw>` | Compliance framework to map findings into (e.g. `soc2`). **Enterprise license required.** See `@nsasoft/nsauditor-ai-ee` README for supported frameworks | — |
699
481
  | `--compliance-scope <path>` | Optional JSON file describing the assessment scope (passed to the compliance engine for cover-page attestation) | — |
700
482
  | `--help`, `-h` | Print usage block (subcommands, flags, env vars, examples) and exit 0 | — |
701
- | `--version`, `-v` | Print `nsauditor-ai <version>` and exit 0 (CE 0.1.30+) | — |
483
+ | `--version`, `-v` | Print `nsauditor-ai <version>` and exit 0 | — |
702
484
 
703
485
  \* Either `--host` or `--host-file` is required.
704
486
 
@@ -930,7 +712,7 @@ No license key? Everything in this repository works perfectly without one. The C
930
712
 
931
713
  ## Tests
932
714
 
933
- Run all 506 tests:
715
+ Run all 925+ tests:
934
716
 
935
717
  ```bash
936
718
  npm test
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { createServer } from '../mcp_server.mjs';
3
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
+ // CE 0.1.37 (SECURITY): delegate to startStdioServer() so the auth
3
+ // check + license verification + rotation warnings actually run.
4
+ // Pre-0.1.37 this file inlined `createServer() + server.connect()`,
5
+ // which silently bypassed the entire startup block in mcp_server.mjs
6
+ // (it was guarded by an argv[1].endsWith('mcp_server.mjs') check that
7
+ // only matched when invoked directly, never via this shim). Result:
8
+ // every Claude Desktop session ran unauthenticated and tier-stuck-at-CE.
9
+ import { startStdioServer } from '../mcp_server.mjs';
4
10
 
5
- const server = createServer();
6
- const transport = new StdioServerTransport();
7
- await server.connect(transport);
11
+ await startStdioServer();
package/mcp_server.mjs CHANGED
@@ -493,16 +493,22 @@ export function createServer() {
493
493
  }
494
494
 
495
495
  // ---------------------------------------------------------------------------
496
- // Standalone entry point
496
+ // Stdio entry point — used by bin/nsauditor-ai-mcp.mjs AND `node mcp_server.mjs`
497
497
  // ---------------------------------------------------------------------------
498
-
499
- const isMainModule =
500
- typeof process !== 'undefined' &&
501
- process.argv[1] &&
502
- (process.argv[1].endsWith('mcp_server.mjs') ||
503
- process.argv[1].endsWith('mcp_server'));
504
-
505
- if (isMainModule) {
498
+ //
499
+ // CE 0.1.37 (SECURITY): this used to be guarded by a brittle
500
+ // `process.argv[1].endsWith('mcp_server.mjs')` check. The bin shim
501
+ // (which Claude Desktop spawns) sets argv[1] to `nsauditor-ai-mcp.mjs`,
502
+ // so the guard was false and the entire startup block — auth check,
503
+ // license verification, rotation warnings — was SKIPPED. Result: Claude
504
+ // Desktop's MCP child ran unauthenticated, with _tier stuck at the CE
505
+ // default, regardless of the operator's installed license. Customers
506
+ // paying for Pro/Enterprise saw "Current tier: CE" responses and lost
507
+ // MCP access to gated tools entirely.
508
+ //
509
+ // Fix: extract the startup into an exported function. The bin shim now
510
+ // calls it explicitly, so the auth + license path runs every time.
511
+ export async function startStdioServer() {
506
512
  // EE-SEC.1: enforce MCP server authentication BEFORE accepting any
507
513
  // tool calls. Pre-fold any process running as the operator could
508
514
  // spawn the server and call Pro/Enterprise tools — including the
@@ -589,4 +595,16 @@ if (isMainModule) {
589
595
  const server = createServer();
590
596
  const transport = new StdioServerTransport();
591
597
  await server.connect(transport);
598
+ return server;
599
+ }
600
+
601
+ // Backward-compat: still callable as `node mcp_server.mjs` directly.
602
+ const isMainModule =
603
+ typeof process !== 'undefined' &&
604
+ process.argv[1] &&
605
+ (process.argv[1].endsWith('mcp_server.mjs') ||
606
+ process.argv[1].endsWith('mcp_server'));
607
+
608
+ if (isMainModule) {
609
+ await startStdioServer();
592
610
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nsauditor-ai",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "Modular AI-assisted network security audit platform — Community Edition",
5
5
  "type": "module",
6
6
  "private": false,