nsauditor-ai-agent-skill 0.2.52 → 0.2.53
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/.claude-plugin/marketplace.json +14 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +6 -4
- package/SKILL.md +52 -34
- package/bin/nsauditor-ai-agent-skill.mjs +142 -0
- package/examples/agent-interactions.md +2 -2
- package/package.json +11 -5
- package/references/plugins.md +1 -1
- package/references/schemas.md +165 -122
- package/references/workflows.md +18 -10
- package/scripts/build_desktop_skill_zip.mjs +217 -0
- package/scripts/frontmatter_contract.mjs +50 -0
- package/CHANGELOG.md +0 -1549
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nsauditor-ai-agent-skill",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Nsasoft US LLC",
|
|
5
|
+
"url": "https://www.nsauditor.com"
|
|
6
|
+
},
|
|
7
|
+
"plugins": [
|
|
8
|
+
{
|
|
9
|
+
"name": "nsauditor-ai",
|
|
10
|
+
"source": "./",
|
|
11
|
+
"description": "Network security auditing and eight-framework compliance evidence with NSAuditor AI, for Claude Code."
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nsauditor-ai",
|
|
3
|
+
"description": "Network security scanning, vulnerability assessment and cloud compliance-evidence auditing with NSAuditor AI, via its MCP server.",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Nsasoft US LLC",
|
|
6
|
+
"url": "https://www.nsauditor.com"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/nsasoft/nsauditor-ai-agent-skill",
|
|
9
|
+
"repository": "https://github.com/nsasoft/nsauditor-ai-agent-skill.git",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": ["nsauditor", "network-security", "vulnerability-assessment", "compliance", "mcp"]
|
|
12
|
+
}
|
package/README.md
CHANGED
|
@@ -13,7 +13,9 @@ Works with **Claude Code**, **Claude Desktop**, **Cursor**, **Windsurf**, **VS C
|
|
|
13
13
|
|
|
14
14
|
## Current release
|
|
15
15
|
|
|
16
|
-
**0.2.
|
|
16
|
+
**0.2.53** — paired with **Enterprise 1.1.0 / Community 0.2.55**. ⚠️ **A floor bump: requires Community >= 0.2.55** (it was >= 0.2.49 — Enterprise 1.1.0 calls code that first ships in Community 0.2.55). The skill now INSTALLS itself: `npx nsauditor-ai-agent-skill install` copies it into `~/.claude/skills/` for Claude Code, and `npx nsauditor-ai-agent-skill build-zip --out ~/Desktop` builds the Claude Desktop upload zip. Claude Code users can instead add it as a plugin marketplace — `/plugin marketplace add nsasoft/nsauditor-ai-agent-skill`. ⚠️ A marketplace reaches **Claude Code only**; Claude Desktop accepts skills only as an uploaded zip, and skills do not sync between surfaces. Knowledge updated for the Pro cross-run delta (`report --since`) that ships in Community 0.2.55.
|
|
17
|
+
|
|
18
|
+
**Prior: 0.2.52** — paired with **Enterprise 1.0.0 / Community 0.2.54** (Community is a README-only release). ⚠️ **NOT a floor bump: Community stays >= 0.2.49.** Plugin enumeration unchanged at 29 Enterprise plugins; all eight coverage matrices unchanged. New in this release's teaching: `Findings analyzed` counts findings rather than issues, so a 1.0.0 pack reads a SMALLER number than a 0.46.0 pack over the same estate and that is the correction — the new `report.summary.findingsReceived` / `findingsRouted` fields let an agent check `findingsRouted ≤ findingCount ≤ findingsReceived` from the pack alone; an Azure RBAC assignment at the root scope (`/`) is named as such; PCI DSS `11.5.2` is critical-file change detection (the payment-page controls are `11.6.1` and `6.4.3`). No tool surface changed. The evidence contract in Enterprise's `docs/contract-v1.md` is binding from EE 1.0.0. See [CHANGELOG.md](https://github.com/nsasoft/nsauditor-ai-agent-skill/blob/main/CHANGELOG.md).
|
|
17
19
|
|
|
18
20
|
**Prior: 0.2.51** — paired with **Enterprise 0.46.0 / Community 0.2.53**. ⚠️ **NOT a floor bump: Community stays >= 0.2.49.** `references/plugins.md` carried the retired `MVP-67` PCI density label; the enumeration is **72 — 19 covered, 9 partial, 44 out of scope with a stated reason**, derived from the shipped framework file. The line already told a reader to call `compliance_matrix` for the current triple and that did not save it: **a pointer beside a hard-coded number does not stop the number rotting; only removing the number does.**
|
|
19
21
|
|
|
@@ -94,7 +96,7 @@ and never that one failed, and must not be reported as tampering. The commands a
|
|
|
94
96
|
**CLI-only**; no MCP tool reaches them, so an agent asked to record an approval must shell out
|
|
95
97
|
rather than look for a tool.
|
|
96
98
|
|
|
97
|
-
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
99
|
+
See [CHANGELOG.md](https://github.com/nsasoft/nsauditor-ai-agent-skill/blob/main/CHANGELOG.md) for the full history.
|
|
98
100
|
|
|
99
101
|
## What's Inside
|
|
100
102
|
|
|
@@ -129,7 +131,7 @@ Claude Code auto-discovers skills in `.claude/skills/`.
|
|
|
129
131
|
|
|
130
132
|
### Claude Desktop
|
|
131
133
|
|
|
132
|
-
Upload `SKILL.md`
|
|
134
|
+
Build the upload zip with `npx nsauditor-ai-agent-skill build-zip --out ~/Desktop`, then upload that `nsauditor-ai-skill-<version>.zip` in Claude Desktop's Settings (skills). Upload the zip, never `SKILL.md` alone: SKILL.md is under half of the skill, and its links to the reference files would point at nothing. Fully quit and relaunch Desktop after replacing a skill.
|
|
133
135
|
|
|
134
136
|
### Cursor
|
|
135
137
|
|
|
@@ -166,7 +168,7 @@ When an AI agent loads this skill, it gains:
|
|
|
166
168
|
| **Security rules** | ZDE, SSRF protection, redaction, scan authorization requirements |
|
|
167
169
|
| **Error handling** | License gates, SSRF blocks, timeout resolution, CPE format errors |
|
|
168
170
|
| **Decision routing** | When to use scan_host vs probe_service vs CLI vs get_vulnerabilities |
|
|
169
|
-
| **Cloud-region scoping** | The MCP `scan_cloud` `regions` argument — pass `["all"]` (or a region-code list like `["us-east-1","eu-west-1"]`) to audit every / specific AWS regions; **omit it
|
|
171
|
+
| **Cloud-region scoping** | The MCP `scan_cloud` `regions` argument — pass `["all"]` (or a region-code list like `["us-east-1","eu-west-1"]`) to audit every / specific AWS regions; **omit it** and the auditors that take their region from the client scan the server-configured `AWS_REGION` only, while the ones that enumerate their own region list (CloudTrail trail discovery, GuardDuty/Inspector, EC2 instances) still attempt every enabled region — pass `["all"]` explicitly to extend every region-scoped check, mindful of the Desktop tool-call timeout. Mirrors the CE CLI `--aws-region <one\|csv\|all>` flag. |
|
|
170
172
|
|
|
171
173
|
## Prerequisites
|
|
172
174
|
|
package/SKILL.md
CHANGED
|
@@ -16,7 +16,7 @@ description: >
|
|
|
16
16
|
|
|
17
17
|
# NSAuditor AI — Agent Skill
|
|
18
18
|
|
|
19
|
-
> **Version:** <!-- nsa:derived id="skill-version" -->0.2.
|
|
19
|
+
> **Version:** <!-- nsa:derived id="skill-version" -->0.2.53<!-- /nsa:derived --> (knowledge current as of **EE <!-- nsa:derived id="ee-version" -->1.1.0<!-- /nsa:derived -->** · **requires CE ≥ <!-- nsa:derived id="ce-floor" -->0.2.55<!-- /nsa:derived -->**) — the delta release: the product can now answer *what changed since the last scan*. Teach three things: (1) **`nsauditor-ai report --from <dir> --since <runId|prior>`** (Pro/Enterprise) compares two runs and reports new / resolved / severity-changed findings. (2) **NEVER present a `resolved` count as remediation on its own** — the report carries a NOT-COMPARABLE bucket with a reason per finding (host not scanned · the producing plugin did not run, ERRORED or TIMED OUT on that host, or cannot be identified · an evidence gap such as AccessDenied · **a PORT that was not measured on that host — a check that could not complete its connection, or a port that STOPPED ANSWERING between the two runs (a port that went quiet is not a fix)** · **the two runs COVERED DIFFERENT SCOPES — a narrower `--aws-region`, a different Azure subscription or GCP project — so that surface was not looked at, which is NOT the same as clean** · framework enumeration moved · **the PRODUCER CHANGED WHAT IT NAMES between the two releases**), and a finding that vanished for any of those reasons was not fixed. ⚠️ **THE LAST ONE IS NEW IN THIS RELEASE AND IT FIRES ON THE UPGRADE ITSELF.** FOURTEEN producers changed what identifies a finding at EE 1.1.0 — thirteen plugins that had left the object empty, named the REGION, recorded no region the report reads, carried a HIGH sentence that had to be corrected (1110, the effective-decrypt auditor), or (1023, the Zero Trust checker) now name the port a finding is about and keep the open-port count out of its title, and one analysis AGENT whose findings are keyed on their TITLE because they carry no object field at all. A comparison that straddles that upgrade reports those rows NOT-COMPARABLE instead of differencing them, so one surface under two keys is never read as a fix plus a fresh exposure. **So the first `report --since` a user runs across the 1.1.0 upgrade will legitimately show a LARGE not-comparable bucket — that is the declaration working, not a broken report.** Derive the reason list from `NOT_COMPARABLE_REASONS` in Community's `utils/scan_delta.mjs` rather than from this sentence; it is held in equality with what the engine emits, and this sentence is prose that has disagreed with it before. If a user asks what got fixed, read the NOT-COMPARABLE list before answering. **Two conditions refuse the whole comparison rather than bucketing findings**: the two runs straddle a product boundary where a reported number changed meaning, and the two runs ran at DIFFERENT LICENCE TIERS — the set of producers that ran differs, so a whole producer's findings would read as remediation. ⚠️ **AND ONE OF THOSE REASONS IS DECLARED RATHER THAN CHECKED: framework-enumeration movement is NOT EVALUATED in this edition**, because a run record carries no framework enumeration. The report says so as a limit on every comparison and each row's basis reads `framework enumeration: not evaluated`. Never tell a user that framework movement was ruled out. (3) **Integrity is a hash chain, not a signature — and say WHAT is sealed.** At finalize the run record AND each written host's findings files are digested over their exact persisted bytes, with the per-file digests sealed inside the record, which is itself digested and chained through `prevDigest`. So an altered **findings file** — which is what the comparison actually reads — is detected and NAMED, not merely an altered index; a file that did not exist at seal time is sealed as an explicit absence, so adding one is detected too. **BOTH runs are verified, not only the baseline.** An altered or unmeasurable run on either side REFUSES the comparison outright, and the refusal names which side. A file that cannot be READ is reported as unmeasurable rather than as tampering, and a record written before per-host sealing keeps its verdict while its reason says the findings files were not covered. The guarantee is tamper-EVIDENT against corruption and unsophisticated edits, **NOT tamper-proof against host-level access and NOT non-repudiation**. Do not describe it as file-integrity monitoring or a change-detection mechanism: PCI DSS `11.5.1` / `11.5.2` / `11.6.1` are enumerated OUT OF SCOPE in the shipped matrix. The code ships in Community; the capability is licence-gated to Pro/Enterprise. ⚠️ **`--since` REQUIRES COMMUNITY 0.2.55 OR LATER, AND THE PEER FLOOR NOW SAYS SO.** It moved to the version in the badge above because **Enterprise CALLS the new Community code** — the per-plugin run statuses the Zero Trust checker reads before it will assert a posture, and the run-record fields `report --since` compares. The earlier floor said otherwise on the grounds that Enterprise did not call it; that stopped being true in this release. If a user reports the flag is unrecognised, check their Community version first. (4) **A `kms:Decrypt on Resource:*` HIGH from 1110 is NEVER downgraded on a live run.** 1110 reads KMS key policies and grants in the configured region only, and one region cannot show that NO key trusts a principal — a key in another region may — so the HIGH→INFO downgrade it used to apply is withheld on every shipped path. The reason is in that plugin's run summary as `summary.kmsDowngrade` (`reason` `single-region-enumeration` for a complete read; `access-denied` · `per-key-error` · `keys-truncated` · `grants-truncated` for an incomplete one, which also emits an evidence-gap row). Never tell a user a surviving HIGH was checked against every key, and never read a missing downgrade as a scanner fault. Its grant finding (`kms-grant-decrypt-no-identity-grant`, MEDIUM) likewise covers keys in the configured region only. (5) **The NVD store and response cache MOVED at EE 1.1.0 and every run records where they are.** They used to be a `.nvd-cache` folder in whatever directory the scan started from; they now resolve, from any directory, to `--cache-dir`, else `NVD_CACHE_DIR`, else `NSAUDITOR_NVD_CACHE_DIR`, else `~/.nsauditor/nvd_cache`. An old `.nvd-cache` folder is NOT read, and the scan says so. If a user reports that offline CVE matching stopped after upgrading, that is the cause: move the folder once or set `NVD_CACHE_DIR` to it. Never read the resulting coverage gaps as a clean host. Plugin count UNCHANGED at <!-- nsa:derived id="plugins:ee" -->29<!-- /nsa:derived -->; <!-- nsa:derived id="matrix-movement" -->all eight coverage matrices unchanged since EE 1.0.0<!-- /nsa:derived -->; Community stays at <!-- nsa:derived id="ce-version" -->0.2.55<!-- /nsa:derived -->.
|
|
20
20
|
>
|
|
21
21
|
> **Prior: 0.2.51** (post-EE-0.46.0 · **requires CE ≥ 0.2.49**) — the PCI-citation-provenance release. **PCI DSS is 19 covered / 9 partial / 44 out of scope across 72 enumerated sub-requirements**; the other seven matrices are unchanged. ⚠️ **Do not cite `4.2.2.1` — it does not exist in PCI DSS v4.0.1** — and do not attribute Customized-Approach ineligibility to any appendix: the standard states it in each requirement's own Customized Approach Objective cell. Sampling is Section 6, which prescribes no sample size. For any PCI triple, call `compliance_matrix` rather than quoting a number from this file.
|
|
22
22
|
>
|
|
@@ -165,13 +165,20 @@ order (discovery → service probes → OS detection → result fusion).
|
|
|
165
165
|
| Parameter | Type | Required | Default | Description |
|
|
166
166
|
|-----------|------|----------|---------|-------------|
|
|
167
167
|
| `host` | string | ✅ | — | Target hostname or IP address |
|
|
168
|
-
| `timeout` | number | ❌ | 30000 | Per-plugin timeout in ms |
|
|
169
168
|
|
|
170
|
-
|
|
169
|
+
Every plugin runs under the server's `PLUGIN_TIMEOUT_MS` (default 30000), including a plugin that
|
|
170
|
+
declares a longer budget of its own; there is no per-call timeout. A plugin that runs out of time
|
|
171
|
+
reads `timeout` in the result's `manifest` — its surface was NOT measured, which is never a clean
|
|
172
|
+
result.
|
|
173
|
+
|
|
174
|
+
**Returns:** `{ host, conclusion, manifest[], pluginsRan, markdown }` — `conclusion.result` is the fused
|
|
175
|
+
record (`summary` is a one-line string; `host`, `services[]`, `evidence[]`), and `manifest[]`
|
|
176
|
+
is every plugin's `{ id, name, status, reason, duration_ms }`. There is no `findings` array. See
|
|
177
|
+
`references/schemas.md`.
|
|
171
178
|
|
|
172
179
|
**Example:**
|
|
173
180
|
```json
|
|
174
|
-
{ "host": "192.168.1.1"
|
|
181
|
+
{ "host": "192.168.1.1" }
|
|
175
182
|
```
|
|
176
183
|
|
|
177
184
|
**Important:**
|
|
@@ -194,6 +201,8 @@ Out of scope, with the control ids and the per-group out-of-scope reasons.
|
|
|
194
201
|
matrix from the plugin inventory, from a scan result, or from documentation — coverage is a property of the shipped
|
|
195
202
|
framework maps, not of the plugin list, and a derived matrix will disagree with the customer's own report.
|
|
196
203
|
|
|
204
|
+
⚠️ **QUOTE the severity header the scan printed — never re-type it from the findings you read.** `scan_cloud` renders one line per provider, `N CRITICAL · N HIGH · N MEDIUM · N LOW · N INFO · N PASS`, and **the INFO column is load-bearing: it carries the evidence gaps and the deferred-scope boundaries.** Re-typing that line while summarising is how the column goes missing — measured 2026-09-18, a GCP reply reported `5 CRITICAL · 2 HIGH · 11 MEDIUM · 0 LOW · 11 PASS` over a header that read `… 0 LOW · 3 INFO · 11 PASS`. Every other number was right. **This is the exact regression the product itself fixed at EE 0.32.11**, when a header could read `…0 LOW · 17 PASS` over 62 unreported INFO records — reproduced one layer up, in the retelling. If you report tiers at all, report every tier the product printed, INFO included, even when it is zero.
|
|
205
|
+
|
|
197
206
|
⚠️ **Never collapse a coverage triple into a single percentage or a "fully covers" figure.** State covered, partial and out of scope as three separate numbers with their ids; a percentage or a "fully" phrasing folds partial into covered and overstates coverage — a 19 / 9 / 44 matrix is 19 covered, not "about 39% fully."
|
|
198
207
|
|
|
199
208
|
⚠️ `outOfScope` is the **flattened sub-criterion count**, not the number of out-of-scope groups: SOC 2 returns 37
|
|
@@ -211,13 +220,15 @@ List all available scanner plugins with metadata.
|
|
|
211
220
|
|-----------|------|----------|-------------|
|
|
212
221
|
| *(none)* | — | — | — |
|
|
213
222
|
|
|
214
|
-
**Returns:** Array of `{ id, name,
|
|
223
|
+
**Returns:** Array of `{ id, name, priority, requirements }`
|
|
215
224
|
|
|
216
225
|
**When to use:** Before a scan to understand available plugins, or to help the user select
|
|
217
226
|
specific plugins for a targeted probe.
|
|
218
227
|
|
|
219
228
|
---
|
|
220
229
|
|
|
230
|
+
### Pro Tools (Pro license required)
|
|
231
|
+
|
|
221
232
|
#### `probe_service` *(Pro license required)*
|
|
222
233
|
Run a single plugin against a specific host:port for deep-dive investigation.
|
|
223
234
|
|
|
@@ -240,9 +251,9 @@ Run a single plugin against a specific host:port for deep-dive investigation.
|
|
|
240
251
|
| 010 | Webapp Detector | Technology stack fingerprinting (Wappalyzer) |
|
|
241
252
|
| 011 | TLS Scanner | TLS versions, cipher suites, deprecation |
|
|
242
253
|
| 014 | NetBIOS Scanner | SMB/NetBIOS enumeration, null sessions |
|
|
243
|
-
| 040 | TLS Cert & Cipher Auditor | Certificate chain, expiry, weak ciphers
|
|
244
|
-
| 050 | TRIBE v2 Probe | Debug leaks, stack traces, CORS misconfig
|
|
245
|
-
| 060 | DNS Security Auditor | SPF/DKIM/DMARC, DNSSEC, zone transfer
|
|
254
|
+
| 040 | TLS Cert & Cipher Auditor | Certificate chain, expiry, weak ciphers |
|
|
255
|
+
| 050 | TRIBE v2 Probe | Debug leaks, stack traces, CORS misconfig |
|
|
256
|
+
| 060 | DNS Security Auditor | SPF/DKIM/DMARC, DNSSEC, zone transfer |
|
|
246
257
|
|
|
247
258
|
---
|
|
248
259
|
|
|
@@ -254,8 +265,9 @@ Look up known CVEs for a CPE string via the NVD 2.0 API.
|
|
|
254
265
|
| `cpe` | string | ✅ | CPE 2.3 format (see CPE guide below) |
|
|
255
266
|
| `maxResults` | number | ❌ | Max CVE results to return |
|
|
256
267
|
|
|
257
|
-
**Returns:** `{ cpe, totalResults,
|
|
258
|
-
CVSS v3.1
|
|
268
|
+
**Returns:** `{ cpe, totalResults, cves[] }` — each CVE is `{ cveId, description, cvssScore, severity,
|
|
269
|
+
vectorString, published, lastModified }`; the CVSS fields are NVD's v3.1 metric, else v3.0, else `null`.
|
|
270
|
+
`totalResults` counts the CVEs returned, after `maxResults`.
|
|
259
271
|
|
|
260
272
|
**CPE Construction Guide:**
|
|
261
273
|
|
|
@@ -278,21 +290,21 @@ Format: `cpe:2.3:a:<vendor>:<product>:<version>:*:*:*:*:*:*:*`
|
|
|
278
290
|
|
|
279
291
|
---
|
|
280
292
|
|
|
281
|
-
###
|
|
293
|
+
### Enterprise Tools (license gated)
|
|
282
294
|
|
|
283
295
|
These tools return a license upgrade prompt on CE installations:
|
|
284
296
|
|
|
285
297
|
| Tool | Tier | Purpose |
|
|
286
298
|
|------|------|---------|
|
|
287
|
-
| `scan_cloud` | Enterprise | Audit one or more cloud accounts (AWS / GCP / Azure) for security & compliance posture using the server-configured credentials. No network host needed. Input: `{ providers?: ("aws"\|"gcp"\|"azure")[], regions?: string[] }` — **pass only the cloud(s) the user names** (`providers:["aws"]` for "audit my AWS account"); omit `providers` only when the user asks to audit ALL clouds. Use this (not `scan_host`) when the user asks to "audit my AWS account", "audit my AWS and Azure accounts", or "check my cloud compliance". CE/Pro callers get an upgrade message. **`regions` (AWS only)** — AWS region codes (e.g. `["us-east-1","eu-west-1"]`) or `["all"]`. **Default —
|
|
299
|
+
| `scan_cloud` | Enterprise | Audit one or more cloud accounts (AWS / GCP / Azure) for security & compliance posture using the server-configured credentials. No network host needed. Input: `{ providers?: ("aws"\|"gcp"\|"azure")[], regions?: string[] }` — **pass only the cloud(s) the user names** (`providers:["aws"]` for "audit my AWS account"); omit `providers` only when the user asks to audit ALL clouds. Use this (not `scan_host`) when the user asks to "audit my AWS account", "audit my AWS and Azure accounts", or "check my cloud compliance". CE/Pro callers get an upgrade message. **`regions` (AWS only)** — AWS region codes (e.g. `["us-east-1","eu-west-1"]`) or `["all"]`. **Default — omit `regions` (MOST requests):** a plain "audit my AWS account", a "quick check", or any request that names no region AND does not explicitly ask for all/every/whole-account/complete/full coverage → **OMIT `regions`** (the auditors that take their region from the client audit the server-configured `AWS_REGION` and no other; the three that enumerate their own region list — CloudTrail trail discovery (1040), GuardDuty/Inspector (1200), EC2 instances (1210) — still attempt every enabled region; do NOT fan out or batch). Omitting does NOT scan all regions with every auditor. **Specific regions:** when the user names region(s), pass exactly those. **All regions — ONLY on an explicit "all regions / every region / whole account / full coverage" request:** use the discover-then-batch approach in the region-scope note below — do NOT pass a single `["all"]` call and rely on it (it fans every regional plugin across all enabled regions and usually EXCEEDS the host's MCP tool-call timeout, e.g. Claude Desktop's, returning nothing). Unknown region codes are rejected before the scan runs (the WHOLE call fails — fix the region and re-call; never silently drop it). |
|
|
288
300
|
| `get_findings` | Enterprise | Drill into the findings of the MOST RECENT `scan_cloud` scan — a per-provider, **per-session** cache (NOT live state; cleared when the MCP server restarts). Input: `{ scanId?, provider?, plugin?, severity?, category?, cursor?, limit? }`. Use it AFTER `scan_cloud` when the summary's **category rollup** shows a category you want to expand to specific resources, or when you need the FULL untruncated text of a finding. Pass the **`scanId` from the `scan_cloud` summary footer** + the `provider`; filter by `category`/`severity`/`plugin`; paginate with `cursor`/`limit` (server-capped at 20 — follow `nextCursor`). If you get a **"re-run scan_cloud"** error the cache was cleared or superseded — **re-run `scan_cloud`, do NOT retry `get_findings`**. CE/Pro callers get the same upgrade message as `scan_cloud`. |
|
|
289
301
|
|
|
290
|
-
> **Interpreting `scan_cloud` results — never report a false clean:** read **`findingsSummary`** for the findings — it maps each provider to `counts` (per-severity totals) and a `findings` list of the CRITICAL/HIGH items (`{severity, plugin, title}`); report those. A cloud was effectively audited only if it appears in `auditedProviders`. If the result has `audited: false`, any `notes` entries, or `pluginsRan: 0`, the cloud was **NOT** audited (no plugins, missing credentials, or skipped) — report the gap explicitly; an empty result is **not** a clean pass. Do not infer "clean" from an empty `findingsSummary` when the cloud is not in `auditedProviders`. **Beyond CRITICAL/HIGH, `findingsSummary[provider].rollup` groups the remaining findings by `category` with counts (count-descending) across **MEDIUM, LOW *and* INFO** — and the INFO tier is not optional reading
|
|
302
|
+
> **Interpreting `scan_cloud` results — never report a false clean:** read **`findingsSummary`** for the findings — it maps each provider to `counts` (per-severity totals) and a `findings` list of the CRITICAL/HIGH items (`{severity, plugin, title}`); report those. A cloud was effectively audited only if it appears in `auditedProviders`. If the result has `audited: false`, any `notes` entries, or `pluginsRan: 0`, the cloud was **NOT** audited (no plugins, missing credentials, or skipped) — report the gap explicitly; an empty result is **not** a clean pass. Do not infer "clean" from an empty `findingsSummary` when the cloud is not in `auditedProviders`. **Beyond CRITICAL/HIGH, `findingsSummary[provider].rollup` groups the remaining findings by `category` with counts (count-descending) across **MEDIUM, LOW *and* INFO** — and the INFO tier is not optional reading: every deferred-scope boundary is INFO, and an evidence gap carries its own finding's severity, which can be any tier up to HIGH, so read every tier. ⚠️ This sentence said "MEDIUM + LOW" until EE 0.39.0, which was FALSE against the summariser's own three rollup buckets, and false in the direction that hides the tier a reader most needs. Report every tier that occurs; these are actionable too: a category like `sqs-age-alarm-missing` or `*-public` is a real gap, not noise, and reporting only CRITICAL/HIGH while the rollup is non-empty is itself a false clean. To enumerate the specific resources behind a rollup category, or to read a finding's full untruncated text, call `get_findings` with the `scanId` from the summary footer + the `category`.**
|
|
291
303
|
|
|
292
|
-
> **Reporting `scan_cloud` region scope — never overstate coverage:** Report the regions you ACTUALLY scanned, derived from the `regions` you **passed** — NOT from the findings. If you OMITTED `regions`, only the
|
|
304
|
+
> **Reporting `scan_cloud` region scope — never overstate coverage:** Report the regions you ACTUALLY scanned, derived from the `regions` you **passed** — NOT from the findings. If you OMITTED `regions`, the auditors that take their region from the client scanned only the server-default region (`AWS_REGION`) — say that, and that the account's OTHER enabled regions were NOT covered by them (offer to re-run for all regions). The three auditors that enumerate their own region list — CloudTrail trail discovery (1040), GuardDuty/Inspector (1200), EC2 instances (1210) — attempt every enabled region when `regions` is omitted. Say one of them covered every region ONLY if it `ran` and carries no multi-region evidence gap (a single-region fallback, or errored or denied regions); any region such a gap names was NOT audited, say so. 1040's CloudWatch-alarm and AWS Config checks cover the configured region only. Never call the whole scan single-region when these three ran. **Never escalate a single-region or "quick" request into a multi-region scan.** Do NOT claim "all regions" / "every region" / "across N regions" for the scan as a whole because those three list per-region findings: their coverage is NOT evidence the other auditors ran outside the region(s) you passed. When you DO pass `regions`, their region-scoped checks follow the list you passed.
|
|
293
305
|
|
|
294
|
-
> **Full all-region coverage — discover then batch** (use ONLY when the user explicitly asked for all/every/whole-account/complete/full region coverage; NEVER for a plain or "quick" request — those stay
|
|
295
|
-
> **⚠️ COMPLIANCE IS A CLI SURFACE, NOT AN MCP TOOL.** `compliance_check` is WITHDRAWN — there is no such tool and there never was, and the evidence pack is produced by `nsauditor-ai scan --host <target> --compliance <fw> --out <dir>`, which runs the compliance PHASE and writes `scan_compliance_<framework>.{json,md,html}` plus its attestation and chain-of-custody sidecars. `scan_cloud`
|
|
306
|
+
> **Full all-region coverage — discover then batch** (use ONLY when the user explicitly asked for all/every/whole-account/complete/full region coverage; NEVER for a plain or "quick" request — those stay on the `regions` default above, with no explicit fan-out): a single `regions:["all"]` call usually exceeds the host's MCP tool-call timeout (e.g. Claude Desktop's) and returns nothing. Reliable pattern: (1) run a default scan (omit `regions`) — its GuardDuty/Inspector findings enumerate every enabled region, giving you the full list while the region-scoped auditors cover the default region; (2) scan the REMAINING regions in small batches (3–5 region codes per `regions:[...]` call) across successive calls until every enabled region is covered; (3) merge and report the TOTAL number of regions actually covered — **count** them, don't guess. If you try `["all"]` and it times out, that result is INCOMPLETE — fall back to batching and continue until complete; never report a timed-out or partial scan as full coverage.
|
|
307
|
+
> **⚠️ COMPLIANCE IS A CLI SURFACE, NOT AN MCP TOOL.** `compliance_check` is WITHDRAWN — there is no such tool and there never was, and the evidence pack is produced by `nsauditor-ai scan --host <target> --compliance <fw> --out <dir>`, which runs the compliance PHASE and writes `scan_compliance_<framework>.{json,md,html}` plus its attestation and chain-of-custody sidecars. `scan_cloud` **never runs that phase** and maps no finding to any framework, so no MCP call produces a pack. Use `compliance_matrix` to state COVERAGE (what is covered / partial / out of scope); use the CLI to produce EVIDENCE.
|
|
296
308
|
>
|
|
297
309
|
> The framework detail below is accurate and worth keeping — it was attached to a tool name that does not exist:
|
|
298
310
|
>
|
|
@@ -403,16 +415,16 @@ Phase 3: INTELLIGENCE (Pro) CPE generation → NVD CVE lookup → Parallel ve
|
|
|
403
415
|
• Service Agent (CVE-specific targeted probes)
|
|
404
416
|
Output: Structured finding queue
|
|
405
417
|
↓
|
|
406
|
-
Phase 4: VERIFICATION
|
|
407
|
-
(
|
|
408
|
-
|
|
418
|
+
Phase 4: VERIFICATION WITHDRAWN — not shipped and not planned. The finding-status
|
|
419
|
+
(withdrawn) field exists; no active probe sets it. Every finding is
|
|
420
|
+
emitted UNVERIFIED.
|
|
409
421
|
↓
|
|
410
422
|
Phase 5: SCORING (Pro/Ent) Risk scoring → Pro AI prompts → Compliance mapping
|
|
411
423
|
Output: Risk report + compliance report (Markdown, HTML, JSON)
|
|
412
424
|
```
|
|
413
425
|
|
|
414
|
-
> **Phase 4 is
|
|
415
|
-
> Verification Engine was withdrawn as a capability claim at EE 0.32.7. Do not describe
|
|
426
|
+
> **Phase 4 is WITHDRAWN and on no roadmap; it stays in the diagram only so the pipeline's shape is
|
|
427
|
+
> legible.** The Verification Engine was withdrawn as a capability claim at EE 0.32.7 and is not planned. Do not describe
|
|
416
428
|
> findings as probe-confirmed (it is WITHDRAWN, not merely unused), and do not tell an
|
|
417
429
|
> operator a finding was "verified" — see
|
|
418
430
|
> `references/schemas.md` § Finding Statuses.
|
|
@@ -426,8 +438,9 @@ shipped plugin files; verify any of them with `nsauditor-ai license --plugins`,
|
|
|
426
438
|
live total and marks each Enterprise plugin `✓ active` or `✗ requires: <tier>`.
|
|
427
439
|
|
|
428
440
|
The Community set groups roughly as service probes, host/network discovery, and intelligence /
|
|
429
|
-
meta plugins
|
|
430
|
-
TRIBE v2 Probe, 060 DNS Security Auditor)
|
|
441
|
+
meta plugins, plus three deep-audit Community plugins (040 TLS Certificate & Cipher Auditor, 050
|
|
442
|
+
TRIBE v2 Probe, 060 DNS Security Auditor): `scan_host` runs them on every tier, and only the
|
|
443
|
+
single-plugin route to them, `probe_service`, needs Pro.
|
|
431
444
|
|
|
432
445
|
> A per-plugin list used to be duplicated here and drifted: it claimed **18** Enterprise plugins
|
|
433
446
|
> while enumerating **15**, against **28** on disk. One catalog, in `references/plugins.md`.
|
|
@@ -452,9 +465,9 @@ User wants to...
|
|
|
452
465
|
├── Check a specific service/port → probe_service (Pro)
|
|
453
466
|
├── Look up CVEs for software version → get_vulnerabilities (Pro)
|
|
454
467
|
├── See available plugins → list_plugins
|
|
455
|
-
├── Audit TLS certificates → probe_service with plugin 040
|
|
456
|
-
├── Check DNS security (SPF/DKIM/DMARC) → probe_service with plugin 060
|
|
457
|
-
├── Detect debug leaks / CORS issues → probe_service with plugin 050
|
|
468
|
+
├── Audit TLS certificates → scan_host, or probe_service (Pro) with plugin 040
|
|
469
|
+
├── Check DNS security (SPF/DKIM/DMARC) → scan_host, or probe_service (Pro) with plugin 060
|
|
470
|
+
├── Detect debug leaks / CORS issues → scan_host, or probe_service (Pro) with plugin 050
|
|
458
471
|
├── Scan a subnet → CLI with --parallel (not MCP)
|
|
459
472
|
├── Set up continuous monitoring → CLI with --watch (not MCP)
|
|
460
473
|
├── State framework COVERAGE → compliance_matrix (any tier)
|
|
@@ -467,10 +480,10 @@ User wants to...
|
|
|
467
480
|
|
|
468
481
|
See `references/schemas.md` for complete structures:
|
|
469
482
|
|
|
470
|
-
- **Scan Result** — `{ summary, host
|
|
483
|
+
- **Scan Result** (`scan_host`) — `{ host, conclusion{ result{ summary, host, services[], evidence[] } }, manifest[], pluginsRan, markdown }`
|
|
471
484
|
- **ServiceRecord** — `{ port, protocol, service, program, version, status, banner, evidence[] }`
|
|
472
|
-
- **Finding** — `{ id, category,
|
|
473
|
-
- **CVE Response** — `{ cpe, totalResults,
|
|
485
|
+
- **Finding** (Pro/Enterprise queue) — `{ id, category, status, title, severity, cvss, target, evidence{ source, cve[], mitre[], raw }, remediation{ summary, effort, references[] }, riskScore }`
|
|
486
|
+
- **CVE Response** (`get_vulnerabilities`) — `{ cpe, totalResults, cves[]{ cveId, cvssScore, severity, vectorString } }`
|
|
474
487
|
- **Plugin Interface** — `{ id, name, priority, run(), conclude(), requirements }`
|
|
475
488
|
- **SARIF Output** — 2.1.0 format for CI/CD consumers
|
|
476
489
|
|
|
@@ -502,7 +515,7 @@ See `references/schemas.md` for complete structures:
|
|
|
502
515
|
|
|
503
516
|
5. **Non-Destructive:** every scanner probe is a read-only query — NSAuditor AI never
|
|
504
517
|
exploits vulnerabilities or modifies target systems. (Active *verification* probes are
|
|
505
|
-
|
|
518
|
+
WITHDRAWN — not shipped and not planned; findings are emitted UNVERIFIED.)
|
|
506
519
|
|
|
507
520
|
---
|
|
508
521
|
|
|
@@ -513,7 +526,8 @@ See `references/schemas.md` for complete structures:
|
|
|
513
526
|
| Variable | Default | Purpose |
|
|
514
527
|
|----------|---------|---------|
|
|
515
528
|
| `NSA_ALLOW_ALL_HOSTS` | unset | Set to `1` to scan RFC 1918 private ranges |
|
|
516
|
-
| `PLUGIN_TIMEOUT_MS` | 30000 |
|
|
529
|
+
| `PLUGIN_TIMEOUT_MS` | 30000 | Per-plugin budget. `scan_host` and `probe_service` bind every plugin to it; on the CLI a plugin that declares its own budget outranks it |
|
|
530
|
+
| `PLUGIN_TIMEOUT_CEILING_MS` | 120000 | Upper bound on any plugin's declared budget — the setting that caps every plugin on the CLI |
|
|
517
531
|
| `AI_ENABLED` | false | Enable AI analysis |
|
|
518
532
|
| `AI_PROVIDER` | openai | `openai` · `claude` · `ollama` |
|
|
519
533
|
| `OPENAI_API_KEY` | — | OpenAI API key (or `keychain:OPENAI_API_KEY`) |
|
|
@@ -577,6 +591,10 @@ claude mcp add nsauditor-ai -- npx nsauditor-ai-mcp
|
|
|
577
591
|
}
|
|
578
592
|
```
|
|
579
593
|
|
|
594
|
+
`PLUGIN_TIMEOUT_MS` bounds each plugin `scan_host` runs, not the call: the plugins run one after
|
|
595
|
+
another, so the call takes roughly the sum of their times and fits inside Claude Desktop's ~60 s
|
|
596
|
+
tool-call limit only when most of them finish quickly.
|
|
597
|
+
|
|
580
598
|
> ⚠️ **`NSA_MCP_AUTH_KEY` is REQUIRED — the server refuses to start without it.** Generate one with
|
|
581
599
|
> `nsauditor-ai mcp install-key`, then put the SAME value in the `env` block above. Without it the MCP
|
|
582
600
|
> server exits at startup and the client shows the tools as unavailable. (`NSA_MCP_AUTH_DISABLE=1`
|
|
@@ -592,7 +610,7 @@ Add to your MCP configuration with the same command/args pattern.
|
|
|
592
610
|
| Edition | Price | Key Features |
|
|
593
611
|
|---------|-------|-------------|
|
|
594
612
|
| **Community** | Free / MIT | 27 plugins (service probes + host/network discovery + intelligence/meta), basic AI, CTEM, SARIF, scan history |
|
|
595
|
-
| **Pro** | $49/mo | + CVE matching, risk scoring, analysis agents,
|
|
613
|
+
| **Pro** | $49/mo | + CVE matching, risk scoring, analysis agents, the single-plugin and CVE-lookup MCP tools (`probe_service`, `get_vulnerabilities`) |
|
|
596
614
|
| **Enterprise** | $2k+/yr | + 29 enterprise plugins (1020-1230 range) — 28 cloud-substrate auditors covering AWS / GCP / Azure plus `1023 Zero Trust Assessment` (which declares no cloud provider and scores zero-trust posture from a NETWORK-host scan — it never runs on a cloud pass, and selecting it by id on its own does not run it either) — against every shipped framework (SOC 2 10 covered + 4 partial; HIPAA; NIST CSF 2.0; PCI DSS v4.0.1; ISO/IEC 27001:2022; CIS Controls v8; GDPR Art. 32 infrastructure substrate; NIST SP 800-171 Rev 2 evidence substrate for CMMC Level 2 preparation); SOC 2 evidence-pack generation; SHA-256 chain-of-custody attestations (RFC 3161 timestamping is opt-in via the `NSAUDITOR_TSA_URL` environment variable — there is no CLI flag and no default, it makes an outbound call to the Time-Stamp Authority you name, and it was exercised against a live Time-Stamp Authority on BOTH delivery vehicles — the npm path and, from inside the pushed `:0.33.0` Marketplace image, on 2026-08-08; retained images `:0.32.11` and earlier carry no `openssl`); air-gapped operation (offline licensing + offline CVE matching under `NSAUDITOR_OFFLINE_ONLY=1`) |
|
|
597
615
|
|
|
598
616
|
→ [Pricing](https://www.nsauditor.com/ai/pricing/)
|
|
@@ -605,7 +623,7 @@ Add to your MCP configuration with the same command/args pattern.
|
|
|
605
623
|
|-------|-------|-----------|
|
|
606
624
|
| SSRF block | Target is loopback/metadata/private | Set `NSA_ALLOW_ALL_HOSTS=1` for local scanning |
|
|
607
625
|
| License gate (`🔒`) | Pro/Enterprise tool on CE | Upgrade license or use CE alternative |
|
|
608
|
-
| Plugin timeout | Network unreachable / slow target |
|
|
626
|
+
| Plugin timeout (`timeout` in `manifest`) | Network unreachable / slow target | Not measured, never clean. Raise `PLUGIN_TIMEOUT_MS` in the server env, or scan from the CLI, where a plugin that declares its own budget gets it |
|
|
609
627
|
| No DNS banner | Provider blocks CHAOS/TXT queries | Expected; not all DNS servers expose version |
|
|
610
628
|
| CPE format error | Malformed CPE string | Use `cpe:2.3:a:vendor:product:version:*:*:*:*:*:*:*` |
|
|
611
629
|
| No services found | Host down or heavily firewalled | Try `NSA_VERBOSE=true` to debug; check connectivity |
|
|
@@ -615,7 +633,7 @@ Add to your MCP configuration with the same command/args pattern.
|
|
|
615
633
|
|
|
616
634
|
## MITRE ATT&CK Mapping
|
|
617
635
|
|
|
618
|
-
|
|
636
|
+
The CLI's report tags what it finds with MITRE techniques (the `scan_host` tool does not return them):
|
|
619
637
|
|
|
620
638
|
| Finding Type | Technique | ID |
|
|
621
639
|
|-------------|-----------|-----|
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The delivery CLI for the NSAuditor AI agent skill.
|
|
3
|
+
//
|
|
4
|
+
// ⚠️ WHY THIS EXISTS: `scripts/build_desktop_skill_zip.mjs` already worked and already took
|
|
5
|
+
// `--out`. It was never DELIVERED — `files[]` excluded `scripts/` and there was no `bin` — so the
|
|
6
|
+
// maintainer used it from a checkout every release while it reached zero users. A capability that
|
|
7
|
+
// ships to nobody is indistinguishable from one that does not exist.
|
|
8
|
+
//
|
|
9
|
+
// ⛔ AN EXPLICIT COMMAND, NEVER A `postinstall`. Writing into $HOME from a postinstall is skipped
|
|
10
|
+
// under `--ignore-scripts`, breaks in CI and sandboxes, orphans files on uninstall, and is a
|
|
11
|
+
// supply-chain shape reviewers distrust. The user asks for the install; the install does not
|
|
12
|
+
// happen to them.
|
|
13
|
+
//
|
|
14
|
+
// ⚠️ THE TWO SURFACES ARE NOT THE SAME AND THE DIFFERENCE IS STRUCTURAL, not an oversight in our
|
|
15
|
+
// packaging: Claude Code loads skills from the FILESYSTEM (`~/.claude/skills/`), so `install` is a
|
|
16
|
+
// copy; Claude Desktop accepts skills ONLY as an uploaded zip through Settings, so `build-zip`
|
|
17
|
+
// makes the artifact and a human uploads it. Skills do not sync between surfaces.
|
|
18
|
+
import fs from 'node:fs';
|
|
19
|
+
import os from 'node:os';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import { spawnSync } from 'node:child_process';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
25
|
+
const SKILL_NAME = 'nsauditor-ai';
|
|
26
|
+
|
|
27
|
+
const USAGE = `nsauditor-ai-agent-skill — deliver the NSAuditor AI skill to a Claude surface
|
|
28
|
+
|
|
29
|
+
nsauditor-ai-agent-skill install [--dest <dir>]
|
|
30
|
+
Copy the skill into Claude Code's skills directory (default ~/.claude/skills).
|
|
31
|
+
Claude Code loads skills from the filesystem; restart is not required.
|
|
32
|
+
|
|
33
|
+
nsauditor-ai-agent-skill build-zip [--out <dir|file>]
|
|
34
|
+
Build the Claude Desktop upload zip. Desktop accepts skills ONLY as a zip
|
|
35
|
+
uploaded through Settings > Features — there is no directory it watches.
|
|
36
|
+
|
|
37
|
+
Skills do NOT sync between Claude Code, Claude Desktop and the API.`;
|
|
38
|
+
|
|
39
|
+
const flag = (argv, name) => {
|
|
40
|
+
const i = argv.indexOf(name);
|
|
41
|
+
if (i === -1) return undefined;
|
|
42
|
+
const v = argv[i + 1];
|
|
43
|
+
// A value-less flag is NOT the same as an absent one: absent means "use the default", while a
|
|
44
|
+
// swallowed value is an operator mistake that must not silently produce the default anyway.
|
|
45
|
+
return v === undefined || v.startsWith('--') ? true : v;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// DERIVED from disk, exactly as the zip builder derives its members. A hand list here would pass
|
|
49
|
+
// its own test while a real install silently dropped a reference file — and a skill that loads
|
|
50
|
+
// without its references degrades quietly rather than failing.
|
|
51
|
+
function members() {
|
|
52
|
+
const refs = fs.readdirSync(path.join(ROOT, 'references'))
|
|
53
|
+
.filter((f) => f.endsWith('.md')).map((f) => `references/${f}`);
|
|
54
|
+
return ['SKILL.md', ...refs];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function install(argv) {
|
|
58
|
+
const destFlag = flag(argv, '--dest');
|
|
59
|
+
if (destFlag === true) {
|
|
60
|
+
console.error('install: --dest needs a directory. A flag that quietly does nothing is how an '
|
|
61
|
+
+ 'operator concludes an install succeeded.');
|
|
62
|
+
return 2;
|
|
63
|
+
}
|
|
64
|
+
const dest = destFlag ?? path.join(os.homedir(), '.claude', 'skills');
|
|
65
|
+
const target = path.join(dest, SKILL_NAME);
|
|
66
|
+
|
|
67
|
+
const list = members();
|
|
68
|
+
const missing = list.filter((m) => !fs.existsSync(path.join(ROOT, m)));
|
|
69
|
+
if (missing.length) {
|
|
70
|
+
// Refuse rather than copy what is present: a partial skill loads and is silently poorer.
|
|
71
|
+
console.error(`install: refusing — these members are missing from the package: ${missing.join(', ')}`);
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
for (const m of list) {
|
|
77
|
+
const to = path.join(target, m);
|
|
78
|
+
fs.mkdirSync(path.dirname(to), { recursive: true });
|
|
79
|
+
fs.copyFileSync(path.join(ROOT, m), to);
|
|
80
|
+
}
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.error(`install: ${e?.message || e}`);
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
console.log(`Installed ${list.length} file(s) to ${target}`);
|
|
86
|
+
console.log('Claude Code will pick it up from the filesystem. This does NOT reach Claude Desktop —');
|
|
87
|
+
console.log('for Desktop run `build-zip` and upload the zip in Settings > Features.');
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildZip(argv) {
|
|
92
|
+
const script = path.join(ROOT, 'scripts', 'build_desktop_skill_zip.mjs');
|
|
93
|
+
// ⚠️ THE BUILDER'S `--out` IS A FILE PATH; THE USEFUL UX IS A DIRECTORY (`--out ~/Desktop`).
|
|
94
|
+
// Handing it a directory throws EISDIR from inside the zip write — a stack trace where the user
|
|
95
|
+
// expected a file. Resolved HERE rather than in the builder, because the builder's contract is
|
|
96
|
+
// guarded (derived members, REQUIRED floor, byte floor, wrapper-folder assertion) and this is a
|
|
97
|
+
// UX concern, not a packaging one. A value-less `--out` is refused for the same reason `install`
|
|
98
|
+
// refuses a value-less `--dest`.
|
|
99
|
+
const out = flag(argv, '--out');
|
|
100
|
+
if (out === true) {
|
|
101
|
+
console.error('build-zip: --out needs a path.');
|
|
102
|
+
return 2;
|
|
103
|
+
}
|
|
104
|
+
let argvOut = argv;
|
|
105
|
+
if (typeof out === 'string') {
|
|
106
|
+
let resolved = out;
|
|
107
|
+
try {
|
|
108
|
+
if (fs.existsSync(out) && fs.statSync(out).isDirectory()) {
|
|
109
|
+
const version = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version;
|
|
110
|
+
resolved = path.join(out, `nsauditor-ai-skill-${version}.zip`);
|
|
111
|
+
}
|
|
112
|
+
} catch { /* fall through with the literal value; the builder reports its own failure */ }
|
|
113
|
+
argvOut = argv.map((a, i) => (i === argv.indexOf('--out') + 1 ? resolved : a));
|
|
114
|
+
}
|
|
115
|
+
if (!fs.existsSync(script)) {
|
|
116
|
+
console.error(`build-zip: the builder is not in this package (${script}). This is the packaging `
|
|
117
|
+
+ 'defect this CLI exists to close — report it rather than working around it.');
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
// SPAWNED, not imported: the builder is a top-level script whose exit codes are its contract
|
|
121
|
+
// (1 = a declared member missing or coverage below the floor). Importing it would swallow them.
|
|
122
|
+
const r = spawnSync(process.execPath, [script, ...argvOut], { stdio: 'inherit' });
|
|
123
|
+
return r.status ?? 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const [verb, ...rest] = process.argv.slice(2);
|
|
127
|
+
let code;
|
|
128
|
+
switch (verb) {
|
|
129
|
+
case 'install': code = install(rest); break;
|
|
130
|
+
case 'build-zip': code = buildZip(rest); break;
|
|
131
|
+
case '--help': case '-h': case 'help': console.log(USAGE); code = 0; break;
|
|
132
|
+
case undefined:
|
|
133
|
+
console.error('nsauditor-ai-agent-skill: a verb is required.\n');
|
|
134
|
+
console.error(USAGE);
|
|
135
|
+
code = 2; break;
|
|
136
|
+
default:
|
|
137
|
+
// Name what was typed. A refusal that does not quote the input reads as a tool failure.
|
|
138
|
+
console.error(`nsauditor-ai-agent-skill: unknown verb \`${verb}\`.\n`);
|
|
139
|
+
console.error(USAGE);
|
|
140
|
+
code = 2;
|
|
141
|
+
}
|
|
142
|
+
process.exit(code);
|
|
@@ -131,12 +131,12 @@ Run:
|
|
|
131
131
|
This rescans every 15 minutes, detects changes (new/removed services, version
|
|
132
132
|
changes, new findings), and sends webhook alerts for high+ severity changes.
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
Each scan appends one line per host to scan_history.jsonl in the output directory (--out, default out/)."
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
---
|
|
138
138
|
|
|
139
|
-
## Example 6: "Audit DNS security for example.com" (Pro)
|
|
139
|
+
## Example 6: "Audit DNS security for example.com" — `probe_service` (Pro); `scan_host` runs 060 on every tier
|
|
140
140
|
|
|
141
141
|
**Agent reasoning:** Use the DNS Security Auditor plugin for comprehensive DNS assessment.
|
|
142
142
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nsauditor-ai-agent-skill",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.53",
|
|
4
4
|
"description": "AI Agent Skill for NSAuditor AI — gives any AI coding agent built-in knowledge of NSAuditor's MCP tools, schemas, plugins, and security audit workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nsauditor",
|
|
@@ -42,13 +42,15 @@
|
|
|
42
42
|
"files": [
|
|
43
43
|
"SKILL.md",
|
|
44
44
|
"README.md",
|
|
45
|
-
"CHANGELOG.md",
|
|
46
45
|
"LICENSE",
|
|
47
46
|
"references/",
|
|
48
|
-
"examples/"
|
|
47
|
+
"examples/",
|
|
48
|
+
"bin/",
|
|
49
|
+
"scripts/",
|
|
50
|
+
".claude-plugin/"
|
|
49
51
|
],
|
|
50
52
|
"peerDependencies": {
|
|
51
|
-
"nsauditor-ai": ">=0.2.
|
|
53
|
+
"nsauditor-ai": ">=0.2.55"
|
|
52
54
|
},
|
|
53
55
|
"peerDependenciesMeta": {
|
|
54
56
|
"nsauditor-ai": {
|
|
@@ -56,6 +58,10 @@
|
|
|
56
58
|
}
|
|
57
59
|
},
|
|
58
60
|
"scripts": {
|
|
59
|
-
"build:desktop-zip": "node scripts/build_desktop_skill_zip.mjs"
|
|
61
|
+
"build:desktop-zip": "node scripts/build_desktop_skill_zip.mjs",
|
|
62
|
+
"test": "node --test"
|
|
63
|
+
},
|
|
64
|
+
"bin": {
|
|
65
|
+
"nsauditor-ai-agent-skill": "bin/nsauditor-ai-agent-skill.mjs"
|
|
60
66
|
}
|
|
61
67
|
}
|
package/references/plugins.md
CHANGED
|
@@ -229,7 +229,7 @@ listings, and default pages.
|
|
|
229
229
|
| 1080 | AWS Lambda Security Auditor | Enterprise | Runtime EOL detection (case-normalized); public function-URL exposure; resource-policy permissive principals; env-var secret-suggestive name detection (ZDE-safe — names only, never values); VPC config; KMS-CMK; DLQ + reserved concurrency | CC6.1 / CC6.6 / CC7.1 / C1.1 |
|
|
230
230
|
| 1090 | AWS Secrets Manager + SSM Parameter Store Auditor | Enterprise | ListSecrets + DescribeSecret (rotation cadence, KMS-CMK, prod-tier tagging) + SSM DescribeParameters (String/SecureString + secret-suggestive name detection). ZDE-critical: NEVER calls GetSecretValue / GetParameter — only metadata APIs | CC6.1 / CC6.6 / C1.1 |
|
|
231
231
|
| 1100 | AWS CodePipeline + CodeBuild Operational Integrity | Enterprise | Pipeline source-stage encryption; CodeBuild `privilegedMode` detection; buildspec inlined-vs-S3 drift; secrets via env vars vs Secrets Manager; IAM role wildcard-Action; S3 artifact-store encryption; stale-execution detection | CC6.1 / CC7.1 / CC8.1 / C1.1 |
|
|
232
|
-
| 1110 | AWS IAM Effective Decrypt-Path Auditor | Enterprise | Cross-plugin reconciler: walks IAM policies for kms:Decrypt / kms:ReEncrypt / kms:GenerateDataKey grants and cross-references against destination KMS key policies (plugin 1070) to compute effective decrypt path; closes NotAction-implicit-decrypt false-PASS class | CC6.1 / CC6.6 / C1.1 / C1.2 |
|
|
232
|
+
| 1110 | AWS IAM Effective Decrypt-Path Auditor | Enterprise | Cross-plugin reconciler: walks IAM policies for kms:Decrypt / kms:ReEncrypt / kms:GenerateDataKey grants and cross-references against destination KMS key policies (plugin 1070) to compute effective decrypt path; closes NotAction-implicit-decrypt false-PASS class. KMS key policies and grants are read in the configured region only, so since EE 1.1.0 the Resource:* HIGH is never downgraded on a live run — `summary.kmsDowngrade` records why | CC6.1 / CC6.6 / C1.1 / C1.2 |
|
|
233
233
|
| 1120 | AWS S3 Lifecycle + Cross-Region Replication Auditor | Enterprise | S3 lifecycle policy enumeration (CC7.1 retention-cadence) + cross-region replication topology (A1.2 DR substrate); destination-bucket reachability verification closes silent-PASS class where replication source FAILED but emitted clean | C1.1 / C1.2 / A1.2 |
|
|
234
234
|
| 1130 | AWS Backup Auditor — headline thread | Enterprise | The largest single-plugin institutional-hardening arc in the EE codebase (~7800 lines, 545 tests). Audits Plans + Vaults + Recovery Points + Selections + Frameworks + Restore Testing + ReportPlans + Legal Holds + VaultType + Vault Tags + Vault Access Policy. **12-dimension air-gapped vault attestation arc** for LogicallyAirGappedBackupVault: 6 cryptographic-isolation mechanisms (vault TYPE + ARN account-segment-separation + destination KMS key-policy clean + destination KMS Grants clean + MRK-replica topology clean + source-account VPC-endpoint policy clean) + 6 substrate dimensions (PITR/retention/encryption/RestoreTesting/Legal Holds/vault Access Policy) | CC6.3 / CC6.6 / CC7.1 / CC8.1 / C1.1 / C1.2 / A1.2 |
|
|
235
235
|
| 1140 | AWS RDS Auditor (v3 — extended in EE 0.4.8) | Enterprise | **10 SOC 2 substrate-evidence dimensions** (v1=3 + v2=4 + v3=3). **v1+v2 (preserved):** Multi-AZ (A1.2) + storage encryption at rest with KMS-key custody classification + **kms:DescribeKey cross-reference promotes UNVERIFIABLE `:key/UUID` ARN shapes to deterministic PASS/MEDIUM** + parameter-group SSL enforcement (postgres rds.force_ssl + mysql require_secure_transport) + BackupRetentionPeriod (7-day baseline) + PubliclyAccessible + IAMDatabaseAuthenticationEnabled + snapshot encryption. **v3 NEW (database audit-logging, EE 0.4.8, v3):dim 8 pgAudit enabled** (postgres-only — `DescribeDBParameters → pgaudit.log` non-empty AND `shared_preload_libraries` contains `pgaudit` token per reviewer fold **false-PASS closure** — Postgres silently ignores the GUC when SPL omits pgaudit; new MEDIUM `rds-pgaudit-misconfigured` category; non-postgres engines = INFO + engine-not-applicable) + **dim 9 CloudWatch Logs exports** (`EnabledCloudwatchLogsExports` engine-dispatched: postgres essential=`postgresql`; mysql/mariadb essential=`error`; oracle essential=`audit`+`trace`; sqlserver essential=`error`; empty=HIGH / partial=MEDIUM / complete=PASS) + **dim 10 CloudWatch Logs retention** (`logs:DescribeLogGroups` enumeration on engine-dispatched prefix per reviewer fold **false-INFO closure**: `/aws/rds/instance/<id>/` for non-Aurora, `/aws/rds/cluster/<DBClusterIdentifier>/` for `aurora-*` engines — pre-fold hard-coded the instance path → 0 log groups on every Aurora node = false-INFO MEDIUM across the whole Aurora fleet; 30-day institutional baseline operator-tunable via `opts.auditLogRetentionPassMinDays` clamped 1..3653). **9 same-session v3 reviewer folds** (HIGH-1 Aurora cluster log-path; MEDIUM-2 pgAudit-SPL cross-check; MEDIUM-3/4/5 cwl-opt-out + retentionDistribution + transient-error distinct categories; LOW-8/9/10 + NIT-12). **Real-AWS smoke END-TO-END against `<operator-test-account>`** (in-place modification of rds-compliant-cluster; cost $0): ALL 3 v3 PASS-path classifiers validated + unmodified rds-violator-db validates HIGH path. **First 0.4.x extension cycle to validate BOTH PASS-path AND HIGH-path classifiers** against real AWS in the same smoke run. | A1.2 / CC6.1 / CC6.6 / C1.1 / CC7.2 / CC7.3 |
|