nsauditor-ai-agent-skill 0.2.53 → 0.2.55
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 +26 -16
- package/SKILL.md +190 -93
- package/examples/agent-interactions.md +100 -68
- package/package.json +2 -2
- package/references/plugins.md +156 -103
- package/references/schemas.md +120 -62
- package/references/workflows.md +150 -67
- package/scripts/frontmatter_contract.mjs +2 -1
package/SKILL.md
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nsauditor-ai
|
|
3
3
|
description: >
|
|
4
|
-
Use
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
development, or non-security topics.
|
|
4
|
+
Use whenever the user wants network security scanning, host reconnaissance or cloud security/compliance
|
|
5
|
+
auditing with NSAuditor AI (MCP tools: scan_host, scan_cloud, get_findings, probe_service,
|
|
6
|
+
get_vulnerabilities, list_plugins, compliance_matrix), or asks about NSAuditor itself: installing or
|
|
7
|
+
upgrading it, Community/Enterprise version compatibility, Enterprise not loading or its output missing
|
|
8
|
+
after an upgrade, what changed in a release, licensing, or reading its reports. Triggers: 'scan',
|
|
9
|
+
'audit', 'vulnerability', 'CVE', 'port scan', 'service detection', 'OS fingerprinting', 'penetration test',
|
|
10
|
+
'TLS/cipher audit', 'certificate check', 'DNS security', 'SPF/DKIM/DMARC/DNSSEC', 'SNMP/SMB/NetBIOS',
|
|
11
|
+
'CTEM', 'continuous monitoring', 'audit my AWS/GCP/Azure account', 'cloud compliance'. Also use it to
|
|
12
|
+
check if a host is up, find open ports or get CVEs for a version, even without the word NSAuditor, when
|
|
13
|
+
its MCP tools are available. Do NOT use for general coding or web development.
|
|
15
14
|
---
|
|
16
15
|
|
|
17
16
|
# NSAuditor AI — Agent Skill
|
|
18
17
|
|
|
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 -->.
|
|
18
|
+
> **Version:** <!-- nsa:derived id="skill-version" -->0.2.55<!-- /nsa:derived --> (knowledge current as of **EE <!-- nsa:derived id="ee-version" -->1.3.0<!-- /nsa:derived -->** · **requires CE ≥ <!-- nsa:derived id="ce-floor" -->0.2.57<!-- /nsa:derived -->**) — **1.3.0: A finding on a port, region or producer a scan did not measure is not counted as fixed, and with SLA tracking on the control it failed is held FAILED — including the prior CVE rows on a service whose lookup failed, the CVE mapper's and the service agent's rows on a TCP port whose service the scan could not identify, and an analysis agent's or the CVE mapper's rows when a plugin they read was left out of the scan or did not complete. Two measured limits: a scan made before EE 1.3.0 could not record a plugin left out of it, so in a comparison with one, an agent's row that scan lacks is not refused — the report's Basis cell says so on the row; and a scan that discovered ports with the Nmap plugin (024) alone records no port oracle, so an analysis agent's or the CVE mapper's row on a port it did not measure can read RESOLVED and count as closed in MTTR, and the control it failed can read PASS — include the port scanner (003).** Teach these first, and never report a row in either limit as fixed, or its control as passing. (a) **The NOT-COMPARABLE bucket catches four more cases.** A UDP-transport finding whose port did not answer in the other run (for a CVE row, also one that answered without identifying its service) is `port-not-measured`, listed with a `/udp` suffix; a CVE row whose LOOKUP failed in the other run is `evidence-gap` — the mapper's own `[COVERAGE GAP] <gapClass> — <protocol>/<service>` record is a coverage gap that opened or cleared, never an exposure; and a finding of an analysis agent that DID NOT RUN (`[COVERAGE GAP] AGENT NOT RUN — <agent> did not run: <cause class>`) is `evidence-gap`, while that agent's controls fail closed in every framework; and a CVE row that VANISHED — present in the baseline, absent now — while the SAME program and version answered on its port in both runs is `vulnerability-data-changed` — the mapper attributes on program and version alone, so the vulnerability data moved (NVD's answer, a cached answer's age, an offline store), not the estate: never present it as a fix, and in MTTR it is not a closed finding. Neither the delta's rule nor MTTR's reaches a port that answers with two different identified programs or versions, and MTTR's does not reach a prior row that recorded no program or version. A CVE that APPEARED on an unchanged service stays NEW with the basis note "the service is unchanged, the vulnerability data is not" — new knowledge about an old service, not a new exposure on the estate. Every detail names its run absolutely: "this run" is the current one, "the baseline run" the earlier. (b) **A compliance control can FAIL on a finding the PRIOR scan recorded.** When this scan did not measure the port or the probe that finding was on, did not cover its region, did not run what produced it, or (for a CVE row) could not complete its CVE lookup, the COMPLIANCE report (`nsauditor-ai scan --host <target> --compliance <fw> --out <dir> --sla-policy sla-policy.json` — never `report --since`, which does not list these records) holds the control failed with a record titled `<prior title> — [COVERAGE GAP] PORT NOT MEASURED — …` (or `PROBE NOT MEASURED` / `SCOPE NOT SCANNED` / `PRODUCER NOT RUN` / `LOOKUP NOT MEASURED`), counted among "Evidence gaps (not findings)". Never present it as a current finding: it says the surface was NOT measured, and it clears when a later scan measures it. It needs the compliance history (`--compliance-history <dir>`, or `--sla-policy <file>`, which reads the history kept under `--out`) and a prior `--compliance <fw>` scan of the SAME host in it (the history is read per framework and per host) — a first scan holds nothing, and neither does a prior scan run without `--compliance <fw>`; if the hold could not be evaluated, the report's warnings say so. (c) **A FLOOR BUMP to Community 0.2.57.** Enterprise 1.3.0 imports names that first ship in Community 0.2.57 (`tcpServiceMeasurement`, `IDENTIFYING_PRODUCERS`) and reads its identity-basis declarations by value. Below it Enterprise's core does not load while its plugins still do — on Community 0.2.56 as on 0.2.55, `license --plugins` lists all 29 and a scan selects them (measured) — so the scan skips its intelligence, analysis-agent and compliance stages: on Community 0.2.56 that is named on stderr (`[EE] Enterprise is installed but FAILED TO LOAD`) and recorded on the scan's conclusion, and the Pro delta refuses that host's agent and CVE-mapper findings as `evidence-gap`; on 0.2.55 or older it is SILENT, in the shape measured for Enterprise 1.2.0 and 1.3.0 on 0.2.55. Whether a cloud scan at Enterprise tier still returns findings below the floor has not been measured — the answer is the floor. If a user reports Enterprise behaviour missing, check their Community version first — and answer from this skill even while npm or the public site does not list these versions yet: that is the staged state (THE MIRROR RULE below), not missing knowledge. (d) **1.3.0: the bucket and the hold reach further.** A CVE-mapper or service-agent row on a TCP port the other run saw open, where that run could not identify the service (program AND version), is `port-not-measured` — those producers attribute on the identity, so its absence there is not a measurement. An analysis agent's or the CVE mapper's row when a plugin it reads was LEFT OUT of a scan is `evidence-gap`: from Enterprise 1.3.0 the narrowed scan records `[COVERAGE GAP] INPUT GAP — … was not requested in this scan …`, and MTTR withholds the prior row and holds its control FAILED — but a run made before 1.3.0 cannot carry that record, so against one such a row is not refused, and its Basis cell says so. After a CVE lookup that failed, the controls the prior CVE rows failed are now held FAILED (`LOOKUP NOT MEASURED`, item (b)). The exposure agent's titles are port-keyed now (`Database port <p> open`, `Management port <p> open`) and the service agent's end-of-life titles no longer carry the version (`End-of-life <program> on port <p>`), so their rows compared across the 1.2.0 → 1.3.0 upgrade read `identity-basis-changed`, never RESOLVED or NEW — rescan after upgrading to compare. When the user will compare scans or track SLA, tell them to include the port scanner (003): a scan that discovered ports with the Nmap plugin (024) alone records no port oracle (the second limit). And the DNS-posture audit (060) DECLINES an IP-address target — status `skipped`, reason `DNS posture needs a domain name — …` — so `dnsSecurity` appears only for a domain name; on an IP-target compliance scan the controls its findings route to (SOC 2 CC6.1, CIS v8 9.5) are held as an evidence gap, with a warning that it could not run, never PASS. The TLS certificate audit (040) grades a name mismatch by the target's form: scanned by ADDRESS, a certificate that names DNS names only reads LOW, its detail ending `the certificate names DNS names only (…); a client connecting by address sees a name mismatch, expected where the service is reached by name`, so it no longer trips `--fail-on high` on its own; a DNS-name target the certificate does not name, a certificate naming a DIFFERENT address and one with no subjectAltName stay HIGH. A certificate with NO subjectAltName — many consumer routers serve one, naming the device only in its CN — says so: `the certificate carries no subjectAltName — modern clients reject it for any name (CN … is not checked)`, because a modern client checks no name in it. 040 also reads IP SANs now (Node prints them `IP Address:`), so a certificate naming the scanned address raises no mismatch, and a name mismatch on a chain the CA store verified no longer adds `ca_not_trusted`. A self-signed certificate still raises `self_signed` HIGH, so a router scanned by address can still fail `--fail-on high`. 040's key-size and signature checks fire on real servers from Community 0.2.57 (they had read fields Node never sets): an RSA key under 2048 bits is `weak_rsa_key` HIGH (CRITICAL under 1024), an EC key under 256 bits `weak_ec_key` HIGH, a CA-issued certificate signed with SHA-1 or MD5 `weak_signature` HIGH, and an issued intermediate signed that way `chain_weak_signature` MEDIUM. A self-signed certificate's own signature is not graded — no client verifies it — and the `self_signed` finding names the algorithm instead. A key of neither type (Ed25519), or a runtime that cannot read signature algorithms (Node 20; Node 24 reads them), records `not assessed` on `certAudit`, never a pass. So a router serving a 1024-bit key now also shows `weak_rsa_key` HIGH. These grades are recorded, not yet routed to a compliance control. The teaching that follows is 0.2.53's, carried forward and still current. — the delta release: the product can now answer *what changed since the last scan*. Teach five things: (1) **`nsauditor-ai report --from <dir> --format executive --since <runId|prior>`** (`--format` is REQUIRED; `report` refuses without it) (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 ARRIVED IN EE 1.1.0 AND IT FIRES ON AN UPGRADE ACROSS 1.1.0.** 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 ENTERPRISE 1.3.0 REQUIRES 0.2.57 (item (c) above).** The peer floor moved to 0.2.55 at EE 1.1.0 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 at EE 1.1.0. 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 `NVD_CACHE_DIR`, else `NSAUDITOR_NVD_CACHE_DIR`, else `~/.nsauditor/nvd_cache`. Only `feed import` (of a feed you downloaded yourself) takes `--cache-dir`; a scan does not read that flag, so it reads a store imported with `--cache-dir <d>` only when that chain resolves to `<d>` (e.g. `NVD_CACHE_DIR=<d>`). The MCP `get_vulnerabilities` cache reads `NSAUDITOR_NVD_CACHE_DIR`, never `NVD_CACHE_DIR`. 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.2.0<!-- /nsa:derived -->; Community <!-- nsa:derived id="ce-version" -->0.2.57<!-- /nsa:derived --> (published with this skill).
|
|
19
|
+
>
|
|
20
|
+
> **Prior: 0.2.54** (post-EE-1.2.0 · **requires CE ≥ 0.2.56**) — **1.2.0: A finding on a port, region or producer a scan did not measure is not counted as fixed, and with SLA tracking on the control it failed is held FAILED. Two measured limits in this release: after a CVE lookup that failed, the prior CVE rows are not counted as fixed, but the controls they failed are not held FAILED and can read PASS; and when two compared scans ran different `--plugins` sets, a row an analysis agent or the CVE mapper derived from a plugin only one of them requested can read RESOLVED or NEW. When the later scan left the plugin out, the row also counts as closed in MTTR and its control can read PASS. Keep `--plugins` identical between compared scans.** Measured then: on Community 0.2.55, Community still loads the Enterprise plugins, and `license --plugins` reports Enterprise 1.2.0 `(loaded)`, but the scan skips its intelligence, analysis-agent and compliance stages without a word. Its other teaching — the NOT-COMPARABLE cases (a), the hold (b) and how a failed Enterprise load surfaces — is carried forward in the header above.
|
|
21
|
+
>
|
|
22
|
+
> **Prior: 0.2.53** (post-EE-1.1.0 · **requires CE ≥ 0.2.55**) — the delta release: `report --since` compares two runs, the NOT-COMPARABLE bucket carries a reason per finding, and integrity is a hash chain over the run record and each host's findings files. Its teaching is carried forward in the header above.
|
|
20
23
|
>
|
|
21
24
|
> **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
25
|
>
|
|
@@ -46,7 +49,7 @@ description: >
|
|
|
46
49
|
> comparing the pack's `generatedAt` against the token's signing time reads host skew more reliably
|
|
47
50
|
> than the withdrawn probe ever could, with a signature behind it. ⚠️ It is an OUTBOUND call to a third
|
|
48
51
|
> party and off by default — say both when you recommend it.
|
|
49
|
-
> **⚠️ THE ATTESTATION'S SHAPE DID NOT CHANGE, and that matters when you help someone
|
|
52
|
+
> **⚠️ THE ATTESTATION'S SHAPE DID NOT CHANGE, and that matters when you help someone read two packs' attestation files side by side** (for what changed in FINDINGS, use `report --since`, never a by-hand diff).
|
|
50
53
|
> `scan_attestation_<fw>.json` still carries all six `ntp` keys — `driftSeconds`, `source`, `note`,
|
|
51
54
|
> `probedAt`, `error`, `staleness` — now as constants, because `nsauditor.scope-attestation/v1` is a
|
|
52
55
|
> frozen schema id and every pack a customer already holds carries them. `staleness.status` is
|
|
@@ -89,9 +92,9 @@ description: >
|
|
|
89
92
|
> *ran* — an envelope carrying neither an error nor a skip flag falls through to *ran*. Teach
|
|
90
93
|
> that `providerStatus` is now answerable per provider (`{ran, skipped, errored}`) and that a
|
|
91
94
|
> provider DISAPPEARING from `auditedProviders` after upgrade is the fix working, not a
|
|
92
|
-
> regression. ⚠️
|
|
93
|
-
> were passing over
|
|
94
|
-
> not the verdicts.
|
|
95
|
+
> regression. ⚠️ Those refusals' compliance verdicts always failed closed, so **never tell a user
|
|
96
|
+
> their controls were passing over that unscanned provider** — they were not; the badge and the
|
|
97
|
+
> reason were wrong, not the verdicts.
|
|
95
98
|
> **(2) An evidence gap states a CAUSE, never an instruction.** The engine quotes a plugin's
|
|
96
99
|
> reason into the *"could not run"* sentence of every control that plugin evidences, and it used
|
|
97
100
|
> to quote the whole thrown message — so the loaders' own `Install: npm install <pkg>@latest`
|
|
@@ -171,9 +174,41 @@ declares a longer budget of its own; there is no per-call timeout. A plugin that
|
|
|
171
174
|
reads `timeout` in the result's `manifest` — its surface was NOT measured, which is never a clean
|
|
172
175
|
result.
|
|
173
176
|
|
|
177
|
+
⚠️ **What `scan_host` returns, and what it does NOT.** Services, the OS, and the flags the service checks leave on
|
|
178
|
+
each service record: weak SSH algorithms, an SNMP default community, weak TLS protocols / ciphers and a self-signed
|
|
179
|
+
certificate, and the MCP server checks — `mcpAnonymousAccess`, `mcpAnonymousToolList`, `mcpCleartextTransport`,
|
|
180
|
+
`mcpDeprecatedProtocol`, `mcpInspectorExposed`. Since Community 0.2.57 the records also carry the HTTP probe's methods
|
|
181
|
+
(006: `dangerousMethods`, with `methodsTested` false when no Allow header was read), the NetBIOS/SMB null-session check
|
|
182
|
+
(014: `nullSessionAllowed` and `shares`), the TLS-certificate audit (040: `certAudit`) and the debug-endpoint audit
|
|
183
|
+
(050: `tribeHealth`, only when TCP 8080 is open). For a domain-name target the DNS-security audit (060: `dnsSecurity`)
|
|
184
|
+
lands on the 53/udp record when the scan found a 53/udp service, otherwise in the conclusion's `evidence`; for an
|
|
185
|
+
IP-address target 060 DECLINES — its `manifest` entry reads `skipped` with the reason, the `markdown` says
|
|
186
|
+
`DNS-security audit (060) not tested`, and nothing lands — so DNS posture is unknown, never clean. Anonymous FTP
|
|
187
|
+
login, zone transfer and the SMB null session are tested only when the MCP server's environment enables them
|
|
188
|
+
(`FTP_CHECK_ANON=true`; `DNS_CHECK_AXFR=true` with `DNS_AXFR_DOMAIN`; `SMB_NULL_SESSION=true`) — all off by default.
|
|
189
|
+
A null `anonymousLogin`, `axfrAllowed`, `nullSessionAllowed` or `dangerousMethods` means NOT TESTED, never "not
|
|
190
|
+
allowed" or "none": `anonymousLoginTested`, `axfrTested` and `nullSessionTested` are `true` when measured, else the
|
|
191
|
+
reason (`opt-in-off`, `no-domain`, `no-answer`). With the Enterprise package, the zero-trust assessment (1023) reaches
|
|
192
|
+
the conclusion only as one score line in its `evidence`, not its per-dimension findings. It does NOT look up CVEs and
|
|
193
|
+
does NOT run the Enterprise analysis agents or exploit intelligence (those run in the CLI scan's enrichment). So
|
|
194
|
+
`Security findings: 0` in its `markdown` is NOT a clean verdict and not a statement that the host has no known
|
|
195
|
+
vulnerabilities: that count is the service-check findings above — the MCP server flags and the 040 / 050 / 060 audit
|
|
196
|
+
entries included — and nothing else. Look CVEs up with `get_vulnerabilities` (Pro) on
|
|
197
|
+
each service whose `cpe` names a concrete version (a `*` version is not a lookup for what is deployed). A service with
|
|
198
|
+
a program and version but `cpe: null` — a program outside the scanner's CPE table; on the measured router, the
|
|
199
|
+
firmware's HTTP server — gets NO lookup from either path: build a CPE for it (`references/workflows.md`), or report its
|
|
200
|
+
CVE coverage as unknown, never as clean. With the Enterprise package and a Pro or Enterprise licence,
|
|
201
|
+
`nsauditor-ai scan --host <host>` runs the CVE mapper and the agents, and joins exploit intelligence when a KEV / EPSS
|
|
202
|
+
store is configured. Measured on a router in an earlier release: the Markdown `scan_host` uses, rendered over the CLI
|
|
203
|
+
scan's own conclusion for that host, read `Security findings: 0` while that CLI scan carried 16 CVEs and 5
|
|
204
|
+
analysis-agent findings, and plugins 040 and 060 had recorded 2 and 3 HIGH findings that did not reach `scan_host`'s
|
|
205
|
+
response then. Those audit entries land on the records now and are counted; the CVEs and the agent findings still are
|
|
206
|
+
not.
|
|
207
|
+
|
|
174
208
|
**Returns:** `{ host, conclusion, manifest[], pluginsRan, markdown }` — `conclusion.result` is the fused
|
|
175
209
|
record (`summary` is a one-line string; `host`, `services[]`, `evidence[]`), and `manifest[]`
|
|
176
|
-
is every plugin's `{ id, name, status, reason, duration_ms }
|
|
210
|
+
is every plugin's `{ id, name, status, reason, duration_ms }`; `pluginsRan` is the number of `manifest[]` entries
|
|
211
|
+
whose status is `ran`. There is no `findings` array. See
|
|
177
212
|
`references/schemas.md`.
|
|
178
213
|
|
|
179
214
|
**Example:**
|
|
@@ -235,7 +270,7 @@ Run a single plugin against a specific host:port for deep-dive investigation.
|
|
|
235
270
|
| Parameter | Type | Required | Description |
|
|
236
271
|
|-----------|------|----------|-------------|
|
|
237
272
|
| `host` | string | ✅ | Target hostname or IP |
|
|
238
|
-
| `pluginName` | string | ✅ | Plugin
|
|
273
|
+
| `pluginName` | string | ✅ | Plugin ID (e.g. `"002"`) or its full `name` as `list_plugins` returns it, in any case (e.g. `"SSH Scanner"`); `ssh_scanner` matches nothing (`Unknown plugin`) |
|
|
239
274
|
| `port` | number | ✅ | Target port number |
|
|
240
275
|
|
|
241
276
|
**Returns:** Raw plugin output with full evidence for that specific service.
|
|
@@ -244,15 +279,15 @@ Run a single plugin against a specific host:port for deep-dive investigation.
|
|
|
244
279
|
| ID | Name | Best For |
|
|
245
280
|
|----|------|----------|
|
|
246
281
|
| 002 | SSH Scanner | Banner, version, weak algorithms/ciphers |
|
|
247
|
-
| 004 | FTP Banner | FTP daemon identification, anonymous login |
|
|
282
|
+
| 004 | FTP Banner Check | FTP daemon identification, anonymous login (only with `FTP_CHECK_ANON=true`) |
|
|
248
283
|
| 006 | HTTP Probe | Server headers, tokens, vendor hints |
|
|
249
284
|
| 007 | SNMP Scanner | Device info via sysDescr, hardware/firmware |
|
|
250
|
-
| 009 |
|
|
251
|
-
| 010 | Webapp Detector | Technology
|
|
252
|
-
| 011 | TLS Scanner | TLS versions, cipher
|
|
253
|
-
| 014 | NetBIOS Scanner | SMB/NetBIOS enumeration, null sessions |
|
|
254
|
-
| 040 | TLS
|
|
255
|
-
| 050 | TRIBE v2 Probe | Debug leaks, stack traces, CORS misconfig |
|
|
285
|
+
| 009 | dns_scanner | DNS server version (CHAOS query) |
|
|
286
|
+
| 010 | Webapp Detector | Technology fingerprinting from a fixed in-house signature table |
|
|
287
|
+
| 011 | TLS Scanner | TLS versions, the cipher negotiated per version, deprecation |
|
|
288
|
+
| 014 | NetBIOS/SMB Scanner | SMB/NetBIOS enumeration, null sessions |
|
|
289
|
+
| 040 | TLS Certificate & Cipher Auditor | Certificate chain, expiry, weak ciphers |
|
|
290
|
+
| 050 | TRIBE v2 Neural API Security Probe | Debug leaks, stack traces, CORS misconfig on a TRIBE v2 API |
|
|
256
291
|
| 060 | DNS Security Auditor | SPF/DKIM/DMARC, DNSSEC, zone transfer |
|
|
257
292
|
|
|
258
293
|
---
|
|
@@ -275,9 +310,9 @@ Format: `cpe:2.3:a:<vendor>:<product>:<version>:*:*:*:*:*:*:*`
|
|
|
275
310
|
|
|
276
311
|
| Detected Program | Detected Version | CPE String |
|
|
277
312
|
|------------------|------------------|------------|
|
|
278
|
-
| OpenSSH | 8.9p1 | `cpe:2.3:a:openbsd:openssh:8.
|
|
313
|
+
| OpenSSH | 8.9p1 | `cpe:2.3:a:openbsd:openssh:8.9:p1:*:*:*:*:*:*` (the suffix is the `update` field) |
|
|
279
314
|
| Apache httpd | 2.4.54 | `cpe:2.3:a:apache:http_server:2.4.54:*:*:*:*:*:*:*` |
|
|
280
|
-
| nginx | 1.24.0 | `cpe:2.3:a:f5:nginx:1.24.0:*:*:*:*:*:*:*` |
|
|
315
|
+
| nginx | 1.24.0 | `cpe:2.3:a:f5:nginx:1.24.0:*:*:*:*:*:*:*` (a `cpe` the scanner returns spells it `nginx:nginx`: if one spelling returns no CVEs, retry with the other; an empty result is not a clean service) |
|
|
281
316
|
| OpenSSL | 3.0.8 | `cpe:2.3:a:openssl:openssl:3.0.8:*:*:*:*:*:*:*` |
|
|
282
317
|
| ISC BIND | 9.18.12 | `cpe:2.3:a:isc:bind:9.18.12:*:*:*:*:*:*:*` |
|
|
283
318
|
| vsftpd | 3.0.5 | `cpe:2.3:a:beasts:vsftpd:3.0.5:*:*:*:*:*:*:*` |
|
|
@@ -308,7 +343,7 @@ These tools return a license upgrade prompt on CE installations:
|
|
|
308
343
|
>
|
|
309
344
|
> The framework detail below is accurate and worth keeping — it was attached to a tool name that does not exist:
|
|
310
345
|
>
|
|
311
|
-
> SOC 2 (AICPA TSC 2017) + HIPAA (§164.312 Technical Safeguards) + NIST CSF 2.0 Core + PCI DSS v4.0.1 (sub-requirement-level for QSA RoC; PCI SSC June 2024 errata) + ISO/IEC 27001:2022 (per-Annex-A-code-level for ISO/IEC 17021-1 certification body assessors; ISO + IEC October 2022; 2013 edition retired October 31, 2025) + **CIS Critical Security Controls v8** (per-Safeguard-level; Center for Internet Security May 2021, v8.1 errata June 2024) + **GDPR Article 32 (Security of Processing)** (sub-measure-level; Regulation (EU) 2016/679; **Art. 32 infrastructure substrate only, NOT GDPR compliance**) gap analysis — all
|
|
346
|
+
> SOC 2 (AICPA TSC 2017) + HIPAA (§164.312 Technical Safeguards) + NIST CSF 2.0 Core + PCI DSS v4.0.1 (sub-requirement-level for QSA RoC; PCI SSC June 2024 errata) + ISO/IEC 27001:2022 (per-Annex-A-code-level for ISO/IEC 17021-1 certification body assessors; ISO + IEC October 2022; 2013 edition retired October 31, 2025) + **CIS Critical Security Controls v8** (per-Safeguard-level; Center for Internet Security May 2021, v8.1 errata June 2024) + **GDPR Article 32 (Security of Processing)** (sub-measure-level; Regulation (EU) 2016/679; **Art. 32 infrastructure substrate only, NOT GDPR compliance**) gap analysis — these and **NIST SP 800-171 Rev 2** (below) have all shipped (SOC 2 EE 0.3.x; HIPAA EE 0.9.0; NIST CSF 2.0 EE 0.10.0; PCI DSS v4.0.1 EE 0.11.0; ISO/IEC 27001:2022 EE 0.12.0; CIS Controls v8 EE 0.13.0; **GDPR Article 32 EE 0.20.0**; NIST SP 800-171 Rev 2 EE 0.40.0). Multi-framework via `--compliance all` (shorthand for every shipped framework; EE 0.31.4) or `--compliance soc2,hipaa,nist-csf,pci-dss,iso-27001,cis-v8,gdpr,nist-800-171` (any CSV subset; aliases `nist`/`pci`/`iso`/`cis`, and `800-171` or `cmmc` for `nist-800-171` — ⚠️ `nist` stays NIST CSF, because two NIST publications now ship and the bare vendor name is ambiguous); an unknown token **fails fast** (no "Framework load failed" stub). One scan produces one complete auditor-ready evidence pack per framework requested. **NIST SP 800-171 Rev 2** (requirement-level `3.x.y` for the matrix, SP 800-171A determination-statement level `3.x.y[a]` for evidence; EE F2 cycle) is the eighth. ⚠️ **TEACH ITS SCOPING DOCTRINE VERBATIM AND NEVER PARAPHRASE IT: "NIST SP 800-171 evidence substrate for CMMC Level 2 preparation."** WITHDRAWN — deliberately not claimed, in these exact words: "CMMC certified / compliant / ready", "FedRAMP authorized", never a MET / NOT MET verdict, and never an SPRS score — a Level 2 certificate is issued to a CONTRACTOR by a C3PAO under the CMMC rule, and FedRAMP authorizes cloud service offerings, which this product is not. Only **2 of the 110** Rev 2 requirements are `covered`, and that is the design rather than a shortfall: one objective scored NOT MET fails its whole requirement, so a requirement is covered only when EVERY one of its determination statements is a statement of technical state the scan reads directly. Each mapped requirement carries `assessmentObjectives` and `objectivesEvidenced`; `partialBasis` names which of three shortfalls applies. CUI scope is the OPERATOR's assertion — the scanner cannot see CUI, cannot tell FCI from CUI, and cannot see an enclave boundary. The SSP (3.12.4) and POA&M (3.12.2) are operator artifacts this engine informs and never produces. ⚠️ Its requirement ids collide EXACTLY with PCI DSS sub-requirement ids (`3.5.1` is real in both), so ALWAYS qualify a citation. **CIS Controls v8**: 17 covered + 23 partial + 113 OOS across 153 Safeguards / 18 Controls. **Implementation Group cumulative discipline** — IG1=56 (cyber-insurance baseline; ~50-70% of mid-market policies require IG1 attestation), IG2 cumulative=130, IG3 cumulative=153; smallest-IG-membership tagging (NEVER report IG2 as 74-of-74 in isolation). **No-certification-body attestation discipline** — engine output is INPUT to CSAT / CIS-CAT Pro self-attestation OR a SOC 2 auditor cross-validating CIS scope, never "CIS certified." Cloud Companion Guide v8 shared-responsibility + CIS-Hardened-Image substrate-evidence credit (Safeguards 4.1/4.2/4.6) + 5 Security Functions (NOT 6 — no Govern) + 6 Asset Types + MS-ISAC/EI-ISAC/H-ISAC sector baselines + v7.1-to-v8 cross-reference. CIS Safeguard examples: `3.3` Data Access Control Lists, `5.4` Restrict Administrator Privileges, `6.3` MFA for Externally-Exposed Applications, `8.2` Collect Audit Logs, `11.4` Isolated Recovery Data Instance. ISO 27001 Annex A code examples: `A.5.15` Access control, `A.5.23` NEW 2022 Cloud services, `A.8.5` Secure authentication, `A.8.9` NEW 2022 Configuration management, `A.8.16` NEW 2022 Monitoring activities, `A.8.24` Use of cryptography. Statement of Applicability per Clause 6.1.3.d discipline + ISMS Clauses 4-10 OOS-by-design framing (7 Major Nonconformity classes — absence of internal audit per Clause 9.2 or management review per Clause 9.3 = auto-fail Stage 2) + 5-attribute taxonomy NEW in 2022 (controlType / informationSecurityProperties / cybersecurityConcepts [5 categories, NOT 6 like NIST CSF 2.0] / operationalCapabilities / securityDomains) + 2013-to-2022 transition discipline. Pair with ISO-aware GRC (Drata ISO 27001 / Vanta ISO 27001 / AuditBoard / OneTrust ISMS / Secureframe ISO 27001) for SoA workflow + internal audit + management review. PCI DSS sub-requirement examples: `Req 1.2.1` NSC config standards, `Req 8.4.1` MFA on non-console admin, `Req 10.2.1` audit logs enabled, `Req 11.3.1` quarterly internal vuln scans. Defined-vs-Customized Approach discipline (PCI DSS v4.0.1 states Customized-Approach ineligibility in each requirement's own Customized Approach Objective cell, not in any appendix; EE ships the derived set in `data/standards/pci-dss-v4_0_1-ids.json`; none of the mapped sub-requirements is Defined-only today, every main-body ineligible id sits in an out-of-scope group, the Appendix A2 / A3 ineligible ids are enumerated in no framework file, and `Req 12.3.2` is a third state — part of the Customized Approach and required of those who use it, neither eligible nor ineligible; CHD Scope operator-attested via CDE DFD per Req 1.2.4; card-brand AOC enforcement view — Visa CISP / Mastercard SDP / Amex DSOP / Discover DISC). **NIST SP 800-171 Rev 2** (evidence substrate for **CMMC Level 2 preparation** — all 110 Rev 2 requirements enumerated, claimed at the SP 800-171A determination-statement level; Rev 2 is pinned because CMMC assesses Rev 2 by rule and Rev 3 is a different 97-requirement universe). ⚠️ **Never tell a user this produces a CMMC certification, FedRAMP authorization, MET/NOT MET verdict or SPRS score — it produces none of those, and each is a C3PAO determination.** **GRC push (Enterprise, opt-in):** set `COMPLIANCE_GRC_PROVIDER=vanta` (or `drata` / `secureframe`) + `COMPLIANCE_GRC_TOKEN` to map the findings to the platform's evidence/test records and push them at scan time (outbound to the vendor you configure; finding content is **NOT redacted by default** — `COMPLIANCE_GRC_REDACTION` unset means `off`, and a Vanta push then carries finding text and `host:port` targets in the clear; set it to `hash` or `remove` to scrub them; token never serialized; the Vanta·Drata·Secureframe connector trio is complete — Secureframe records model; all three are early-access and live-tenant validation is not yet complete).
|
|
312
347
|
|
|
313
348
|
### Evidence gaps — never read one as a pass (post EE 0.32.9)
|
|
314
349
|
|
|
@@ -351,7 +386,7 @@ assessed.** State this as a per-plugin invariant, never as a provider roster: a
|
|
|
351
386
|
stale on the next Enterprise release, which is exactly why the CE tool description stopped carrying
|
|
352
387
|
one at CE 0.2.44.
|
|
353
388
|
|
|
354
|
-
Since EE 0.39.0 all three clouds declare: AWS through
|
|
389
|
+
Since EE 0.39.0 all three clouds declare: AWS through eleven plugins (1020 through its S3 access-point helper, then 1060, 1070, 1080, 1090, 1100, 1110, 1120, 1130, 1140 and 1230 — 1140 and 1230 declare since EE 0.41.0), Azure through four (1022, 1220,
|
|
355
390
|
1221, 1222) and GCP through three (1021, 1024, 1025). Before that release only AWS declared, and the
|
|
356
391
|
asymmetry was itself the hazard — **one provider disclosing is what makes another's silence read as
|
|
357
392
|
completeness.** The AWS declarations are also now emitted once per RUN rather than once per region,
|
|
@@ -365,33 +400,42 @@ a mapping from general security knowledge.** The engine deliberately routes some
|
|
|
365
400
|
*narrowly*, and a plausible-looking freehand mapping will overclaim. The non-obvious
|
|
366
401
|
dispositions to know:
|
|
367
402
|
|
|
368
|
-
- **Missing HSTS header → SOC 2 CC6.7
|
|
369
|
-
§164.312(e)(1), ISO A.8.9, CIS 3.10, NIST CSF, PCI DSS, or GDPR.
|
|
370
|
-
on an endpoint whose transport **is** encrypted (the header governs
|
|
371
|
-
downgrade, not the observed session), so failing a transmission-security
|
|
372
|
-
secure-configuration control in
|
|
373
|
-
overclaim — a Required HIPAA standard or
|
|
374
|
-
inference.
|
|
403
|
+
- **Missing HSTS header → SOC 2 CC6.7 and NIST SP 800-171 3.13.15.** It is deliberately
|
|
404
|
+
**not** mapped to HIPAA §164.312(e)(1), ISO A.8.9, CIS 3.10, NIST CSF 2.0, PCI DSS, or GDPR.
|
|
405
|
+
The finding fires only on an endpoint whose transport **is** encrypted (the header governs
|
|
406
|
+
a *future* client's downgrade, not the observed session), so failing a transmission-security
|
|
407
|
+
or secure-configuration control in those frameworks on one absent response header would
|
|
408
|
+
overclaim — a Required HIPAA standard or a CIS Safeguard flipped on a single-header
|
|
409
|
+
inference. The 800-171 rule routes it to 3.13.15 (authenticity of communications sessions),
|
|
410
|
+
a **partial** requirement; its rationale reads the finding as corroborating substrate that
|
|
411
|
+
applies where the operator asserts the endpoint serves CUI-bearing sessions. (EE 0.32.7 cut
|
|
412
|
+
the routing to SOC 2 alone; the 800-171 rule arrived with that framework in EE 0.40.0.)
|
|
413
|
+
**It fires on port 443 only, where the HTTP probe (006) received the HTTPS response:** since Community 0.2.57 that
|
|
414
|
+
probe keeps the `Strict-Transport-Security` header on its port-443 HTTPS record, and the CLI scan's crypto agent
|
|
415
|
+
(Enterprise package, Pro or Enterprise licence) reads it there. On any other port, over plain HTTP, or where no HTTPS
|
|
416
|
+
response arrived (a certificate the client rejects needs `--insecure-https`), the header is not read, so the absence
|
|
417
|
+
of this finding says nothing about whether HSTS is set there.
|
|
375
418
|
- **Aggregate open-port count** and the **opportunistic-STARTTLS / port-inferred cleartext**
|
|
376
|
-
variants
|
|
419
|
+
variants route to **SOC 2 only** — each is a breadth heuristic or a self-declared
|
|
377
420
|
*unverifiable* observation, not a per-transmission determination.
|
|
378
|
-
- Otherwise, network-scan analysis-agent findings (`crypto_agent` / `exposure_agent`)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
421
|
+
- Otherwise, network-scan analysis-agent findings (`crypto_agent` / `exposure_agent`) route
|
|
422
|
+
across **every shipped** framework where the control subject matches: a **confirmed**
|
|
423
|
+
cleartext channel fails HIPAA §164.312(e)(1), ISO A.8.24, NIST CSF PR.DS-02, CIS 3.10,
|
|
424
|
+
PCI DSS 4.2.1, GDPR Art.32(1)(a)-encryption-in-transit, NIST SP 800-171 3.13.8 and
|
|
425
|
+
SOC 2 CC6.7, among other controls — read the full list from the pack.
|
|
382
426
|
|
|
383
427
|
If unsure, say the pack is what decides it and offer to run the CLI — never assert a control
|
|
384
428
|
mapping the engine did not emit, and never claim an MCP call produced a pack.
|
|
385
429
|
|
|
386
430
|
---
|
|
387
431
|
|
|
388
|
-
### Suppressions — the workflow SHIPS
|
|
432
|
+
### Suppressions — the workflow SHIPS; signing an approval is opt-in (proven at EE 0.36.0)
|
|
389
433
|
|
|
390
|
-
An operator can
|
|
434
|
+
An operator can suppress a compliance violation as accepted-risk or false-positive (`nsauditor-ai compliance suppress … --status <accepted_risk|false_positive>`, Enterprise). That suppression workflow **ships and is reachable** from the CLI; it is not an MCP tool. The report lists each suppressed finding with its OWN suppression's status — ACCEPTED RISK or FALSE POSITIVE — and its approver. A control whose violations are ALL suppressed reads FALSE POSITIVE when every one of those suppressions is a false positive and ACCEPTED RISK otherwise; one unsuppressed violation keeps the control FAIL. (The finding-queue status `FALSE_POSITIVE` in `references/schemas.md` is a different field.) The suppression is applied before the pack is written, so it sits **inside** the hashed artifact.
|
|
391
435
|
|
|
392
|
-
⚠️ **Ed25519 SIGNING of suppressions became reachable in EE 0.35.0 via `compliance suppress` and was PROVEN at EE 0.36.0, verified for approvers whose registry entry carries key material** — the verification gate ran against the published bytes and passed, tamper negative control included. Present a produced signature as verified evidence only **for approvers whose registry entry carries key material**; a fingerprint-only registry entry makes a report read `not checked by this report`, which records that no check ran and must never be reported as a failure. The signer backends and the frozen `algorithm` / `backend` record fields are groundwork, deliberately landed before reachability because retrofitting algorithm agility once signatures exist in customer archives would break every auditor holding one.
|
|
436
|
+
⚠️ **Ed25519 SIGNING of suppressions became reachable in EE 0.35.0 via `compliance suppress` and was PROVEN at EE 0.36.0, verified for approvers whose registry entry carries key material** — the verification gate ran against the published bytes and passed, tamper negative control included. Present a produced signature as verified evidence only **for approvers whose registry entry carries key material**; a fingerprint-only registry entry makes a report read `not checked by this report`, which records that no check ran and must never be reported as a failure. The signer backends and the frozen `algorithm` / `backend` record fields are groundwork, deliberately landed before reachability because retrofitting algorithm agility once signatures exist in customer archives would break every auditor holding one. How it is produced: `nsauditor-ai compliance keygen --key <path>` writes an Ed25519 keypair (private half `0600`) and prints the identity-registry member to paste, including the public key material a report needs to verify; while `NSAUDITOR_SIGNING_KEY` names that local key file, `compliance suppress` signs the approval it writes, and without it the approval is recorded unsigned and the report says `unsigned — documentation-only approval` (a KMS or keychain reference is refused at the command). Where the approver's registry entry carries that key material, a signature that verifies renders `signed (approver)`, `signed (deployment)` or `signed, identity model not declared`, and a one-character edit to the approval's signed content renders `🔴 signature FAILED verification`, with the attestation at `not_authenticated`. Even verified, `approver` is the operator's DECLARATION — the signature proves the registered key signed the record, not who holds that key; corroborate against the identity registry. Setting the key later does not sign approvals already recorded, and `compliance renew` on a signed approval invalidates its signature (re-approve with the key configured instead).
|
|
393
437
|
|
|
394
|
-
**
|
|
438
|
+
**Call an approval's signature verified only where the report's attestation for it reads `signed (…)` or `signed, identity model not declared`.** `unsigned` is a documentation-only approval. `signature NOT authenticated` — in an Appendix B cell, `🔴 signature FAILED verification` or a `signed — …` qualifier such as `not checked by this report` — means nothing may lean on that signature; only `FAILED verification` says the record and its signature disagree (tampering, or a `renew` after signing). If asked what the SHA-256 chain-of-custody covers: each framework's `scan_chain_of_custody_<fw>.json` lists the artifacts it covers with their digests, beside a `.sha256` sidecar per file. On its own a digest detects corruption, or an edit by something that did not recompute it; it cannot prove the pack was unaltered, because whoever edits an artifact can recompute its digest. If the operator signed that envelope with `compliance sign-pack`, `compliance verify-pack` exposes an edit by anyone who cannot re-sign — for that one framework's envelope and the artifacts it enumerates, under an operator-held key. An opt-in RFC 3161 `.tsr` (`NSAUDITOR_TSA_URL`) fixes each timestamped artifact's digest at the Time-Stamp Authority's time, so a later edit cannot be backdated. None of these says who suppressed a finding or why — the suppression record does (approver, rationale, dates), and only a signature the report verifies ties it to a registered key; an assessor asking about suppressions usually wants that.
|
|
395
439
|
|
|
396
440
|
⚠️ **Disambiguation:** "suppression" also appears in this package in the unrelated **AWS SES email suppression list** sense (plugin 1190). They are different subjects; check which one is being asked about.
|
|
397
441
|
|
|
@@ -408,16 +452,21 @@ Phase 2: BASIC ANALYSIS (CE) Redaction → MITRE mapping → AI analysis (any
|
|
|
408
452
|
↓
|
|
409
453
|
[ License Gate: Pro required ]
|
|
410
454
|
↓
|
|
411
|
-
Phase 3: INTELLIGENCE (Pro) CPE generation → NVD CVE lookup →
|
|
412
|
-
|
|
455
|
+
Phase 3: INTELLIGENCE (Pro) CPE generation → NVD CVE lookup → parallel ANALYSIS agents, which
|
|
456
|
+
read the collected scan evidence and send no probes of their own:
|
|
457
|
+
• Auth Agent (Telnet, default SNMP community; anonymous FTP only
|
|
458
|
+
with FTP_CHECK_ANON=true)
|
|
413
459
|
• Crypto Agent (TLS, ciphers, certificates)
|
|
414
|
-
• Config Agent (
|
|
415
|
-
• Service Agent (
|
|
460
|
+
• Config Agent (default SNMP community; RPC / NetBIOS open on a Linux host)
|
|
461
|
+
• Service Agent (end-of-life versions, from an offline table)
|
|
462
|
+
• Exposure Agent, Enterprise only (open database, management and
|
|
463
|
+
lateral-movement ports)
|
|
416
464
|
Output: Structured finding queue
|
|
417
465
|
↓
|
|
418
466
|
Phase 4: VERIFICATION WITHDRAWN — not shipped and not planned. The finding-status
|
|
419
467
|
(withdrawn) field exists; no active probe sets it. Every finding is
|
|
420
|
-
emitted UNVERIFIED
|
|
468
|
+
emitted UNVERIFIED, which never means "tried and could not be
|
|
469
|
+
confirmed" (see Security Constraints, item 5).
|
|
421
470
|
↓
|
|
422
471
|
Phase 5: SCORING (Pro/Ent) Risk scoring → Pro AI prompts → Compliance mapping
|
|
423
472
|
Output: Risk report + compliance report (Markdown, HTML, JSON)
|
|
@@ -439,8 +488,10 @@ live total and marks each Enterprise plugin `✓ active` or `✗ requires: <tier
|
|
|
439
488
|
|
|
440
489
|
The Community set groups roughly as service probes, host/network discovery, and intelligence /
|
|
441
490
|
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
|
|
443
|
-
|
|
491
|
+
TRIBE v2 Neural API Security Probe, 060 DNS Security Auditor): `scan_host` runs them on every tier (050 only when
|
|
492
|
+
TCP 8080 is open) and returns their findings on the records — `certAudit`, `tribeHealth`, `dnsSecurity` (060's only for
|
|
493
|
+
a domain-name target, in the conclusion's evidence when the scan found no 53/udp service; it declines an IP address);
|
|
494
|
+
`probe_service` (Pro) runs one of them against one port.
|
|
444
495
|
|
|
445
496
|
> A per-plugin list used to be duplicated here and drifted: it claimed **18** Enterprise plugins
|
|
446
497
|
> while enumerating **15**, against **28** on disk. One catalog, in `references/plugins.md`.
|
|
@@ -449,27 +500,41 @@ single-plugin route to them, `probe_service`, needs Pro.
|
|
|
449
500
|
|
|
450
501
|
See `references/workflows.md` for detailed multi-step patterns:
|
|
451
502
|
|
|
452
|
-
1. **Full Security Audit** — list_plugins → scan_host → get_vulnerabilities per service
|
|
503
|
+
1. **Full Security Audit** — list_plugins → scan_host → get_vulnerabilities per service (over MCP: no analysis
|
|
504
|
+
agents and no exploit intelligence — the CLI scan runs them)
|
|
453
505
|
2. **Targeted Service Investigation** — probe_service(pluginId) → get_vulnerabilities
|
|
454
506
|
3. **Subnet Discovery** — CLI: `nsauditor-ai scan --host <CIDR> --parallel 10`
|
|
455
507
|
4. **CI/CD Pipeline** — SARIF output with `--fail-on` severity gating
|
|
456
|
-
5. **Continuous Monitoring (CTEM)** — `--watch --interval <min> --webhook-url <url>`
|
|
508
|
+
5. **Continuous Monitoring (CTEM)** — `--watch --interval <min> --webhook-url <url>` (its webhook alerts a host
|
|
509
|
+
whose scan changed and that carries a finding at or above `--alert-severity`; the first cycle sets the baseline
|
|
510
|
+
and alerts nobody — `references/workflows.md` §5)
|
|
457
511
|
6. **AI-Powered Report** — Scan with AI provider (OpenAI/Claude/Ollama) + redaction
|
|
458
512
|
|
|
459
513
|
### Decision Tree: Which Tool to Use
|
|
460
514
|
|
|
461
515
|
```
|
|
462
516
|
User wants to...
|
|
463
|
-
├── Scan a host comprehensively → scan_host
|
|
517
|
+
├── Scan a host comprehensively → scan_host (services + service checks; NO CVE lookup —
|
|
518
|
+
│ follow with get_vulnerabilities per service `cpe`, or the CLI scan)
|
|
464
519
|
├── Audit a cloud account (AWS/GCP/Azure) → scan_cloud (Enterprise)
|
|
465
520
|
├── Check a specific service/port → probe_service (Pro)
|
|
466
521
|
├── Look up CVEs for software version → get_vulnerabilities (Pro)
|
|
467
522
|
├── See available plugins → list_plugins
|
|
468
|
-
├── Audit TLS certificates →
|
|
469
|
-
|
|
470
|
-
├──
|
|
523
|
+
├── Audit TLS certificates → probe_service (Pro) with plugin 040, one port — or scan_host:
|
|
524
|
+
│ `certAudit` on each port 040 audited
|
|
525
|
+
├── Check DNS security (SPF/DKIM/DMARC) → probe_service (Pro) with plugin 060 — or scan_host on the domain name:
|
|
526
|
+
│ `dnsSecurity` (on the 53/udp record, else in the conclusion's evidence)
|
|
527
|
+
├── Detect debug leaks / CORS issues → probe_service (Pro) with plugin 050 — or scan_host: `tribeHealth`,
|
|
528
|
+
│ only when TCP 8080 is open
|
|
471
529
|
├── Scan a subnet → CLI with --parallel (not MCP)
|
|
472
530
|
├── Set up continuous monitoring → CLI with --watch (not MCP)
|
|
531
|
+
│ (its webhook alerts a changed host carrying a finding at or above
|
|
532
|
+
│ --alert-severity; never on the first cycle — workflows.md §5)
|
|
533
|
+
├── Compare two scans → CLI (Pro): report --from <dir> --format executive --since prior
|
|
534
|
+
│ (not MCP; NEVER by hand — a by-hand diff reads a finding that
|
|
535
|
+
│ vanished unmeasured as fixed; report --since refuses it, but
|
|
536
|
+
│ the header's two measured limits still apply — compare runs
|
|
537
|
+
│ made by Enterprise 1.3.0 or later, and include the port scanner 003)
|
|
473
538
|
├── State framework COVERAGE → compliance_matrix (any tier)
|
|
474
539
|
└── Produce a compliance EVIDENCE PACK → CLI with --compliance (not MCP)
|
|
475
540
|
```
|
|
@@ -493,29 +558,51 @@ See `references/schemas.md` for complete structures:
|
|
|
493
558
|
|
|
494
559
|
**CRITICAL — Always observe these constraints:**
|
|
495
560
|
|
|
496
|
-
1. **Zero Data Exfiltration (ZDE)
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
561
|
+
1. **Zero Data Exfiltration (ZDE)** is a claim about a PARTY, not about the host:
|
|
562
|
+
No customer data is collected, transmitted, or stored by Nsasoft US LLC. Scan-derived data can
|
|
563
|
+
reach third parties. ON BY DEFAULT at Pro and above: CVE matching queries NIST's NVD with the CPE
|
|
564
|
+
(vendor, product, exact version) of each detected service that local NVD data does not already
|
|
565
|
+
answer; `NSAUDITOR_OFFLINE_ONLY=1` turns that off (CVE matching then needs a populated local NVD
|
|
566
|
+
store). OPT-IN: AI analysis (redaction below); GRC push (finding text plus host:port identifiers,
|
|
567
|
+
sent as they are unless `COMPLIANCE_GRC_REDACTION` is `hash` or `remove`, which fingerprints or
|
|
568
|
+
removes both); `--webhook-url` alerts (findings in the clear); and `get_vulnerabilities` (the CPE
|
|
569
|
+
it is given, to NVD; `NSAUDITOR_OFFLINE_ONLY` does not stop it). EE's egress register
|
|
570
|
+
(`utils/egress_register.mjs`) lists the outbound paths, each with its trigger and whether it is on
|
|
571
|
+
by default. Never tell a user "nothing leaves", and never suggest enabling an opt-in path without
|
|
572
|
+
the user's decision.
|
|
573
|
+
|
|
574
|
+
2. **SSRF Protection:** The MCP server refuses loopback, unspecified, link-local and cloud-metadata addresses
|
|
575
|
+
(`169.254.169.254`, `100.100.100.200`, `fd00:ec2::254`) in any spelling, whether written as the target or returned
|
|
576
|
+
for a host name — every answer is checked — and refuses a name that does not resolve. Private ranges (RFC 1918,
|
|
577
|
+
CGNAT `100.64/10`, `fc00::/7`) are refused too unless `NSA_ALLOW_ALL_HOSTS` is `1`, `true`, `yes` or `on`, which
|
|
578
|
+
admits private ranges only, never loopback, link-local or metadata. It takes one host: a CIDR or URL-shaped string
|
|
579
|
+
is refused. The check does not pin the answer, so a name whose answer changes between the check and the scan (DNS
|
|
580
|
+
rebinding) is not caught. Set the variable **only** for legitimate local network auditing.
|
|
581
|
+
|
|
582
|
+
3. **AI Redaction:** with AI analysis on and `OPENAI_REDACT` at its default (on), the scan payload
|
|
583
|
+
(host, summary, services, evidence) is scrubbed at every tier: the host field becomes
|
|
584
|
+
`[REDACTED_HOST]`; private IPv4 becomes `[REDACTED_HOST]` in the summary and `[REDACTED_IP]` in
|
|
585
|
+
services and evidence; public IPv4 becomes `[IP]`; link-local and full-form IPv6 and colon-form
|
|
586
|
+
MACs (`[MAC]`) are masked; serial numbers become `[REDACTED_HIDDEN]`, as do values under keys
|
|
587
|
+
containing a word listed in `CONFIDENTIAL_KEYWORDS` (empty by default). **That payload is NOT
|
|
588
|
+
scrubbed of** email addresses, internal hostnames, SNMP community strings, Bearer tokens, AWS keys,
|
|
589
|
+
file paths or compressed IPv6 (`2001:db8::1`); ports, service names, versions and other evidence
|
|
590
|
+
text go as they are. At Pro and above, the findings block added to the prompt is also masked by
|
|
591
|
+
default: target hosts, private IPv4, emails, MACs, internal hostnames and `community=<value>`
|
|
592
|
+
strings (a community quoted in a finding title is not); AWS keys, Bearer tokens and file paths
|
|
593
|
+
only with `NSA_AI_REDACT_LEVEL=strict`. With Ollama at its default localhost URL, the AI call
|
|
594
|
+
stays on the host.
|
|
512
595
|
|
|
513
596
|
4. **Scan Authorization:** ALWAYS confirm the user has authorization to scan the target.
|
|
514
597
|
Never scan hosts without explicit user instruction. Unauthorized scanning is illegal.
|
|
515
598
|
|
|
516
599
|
5. **Non-Destructive:** every scanner probe is a read-only query — NSAuditor AI never
|
|
517
600
|
exploits vulnerabilities or modifies target systems. (Active *verification* probes are
|
|
518
|
-
WITHDRAWN — not shipped and not planned; findings are emitted UNVERIFIED.)
|
|
601
|
+
WITHDRAWN — not shipped and not planned; findings are emitted UNVERIFIED.) Every row of the
|
|
602
|
+
finding queue carries `UNVERIFIED`, `[COVERAGE GAP]` rows included, so the status says nothing
|
|
603
|
+
about a row: report a finding as what the scanner detected, never as "tried and could not be
|
|
604
|
+
confirmed". What says a check did NOT measure is a `[COVERAGE GAP]` title, an
|
|
605
|
+
`evidenceGap: true` marker or a `coverage UNVERIFIED` summary line.
|
|
519
606
|
|
|
520
607
|
---
|
|
521
608
|
|
|
@@ -525,7 +612,7 @@ See `references/schemas.md` for complete structures:
|
|
|
525
612
|
|
|
526
613
|
| Variable | Default | Purpose |
|
|
527
614
|
|----------|---------|---------|
|
|
528
|
-
| `NSA_ALLOW_ALL_HOSTS` | unset |
|
|
615
|
+
| `NSA_ALLOW_ALL_HOSTS` | unset | `1`, `true`, `yes` or `on` (nothing else) admits private ranges — RFC 1918, CGNAT, `fc00::/7`. Over MCP it never admits loopback, link-local or metadata; on the CLI it lifts the whole scan-entry guard |
|
|
529
616
|
| `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
617
|
| `PLUGIN_TIMEOUT_CEILING_MS` | 120000 | Upper bound on any plugin's declared budget — the setting that caps every plugin on the CLI |
|
|
531
618
|
| `AI_ENABLED` | false | Enable AI analysis |
|
|
@@ -533,13 +620,15 @@ See `references/schemas.md` for complete structures:
|
|
|
533
620
|
| `OPENAI_API_KEY` | — | OpenAI API key (or `keychain:OPENAI_API_KEY`) |
|
|
534
621
|
| `ANTHROPIC_API_KEY` | — | Claude/Anthropic API key |
|
|
535
622
|
| `OPENAI_MODEL` | gpt-4o-mini | OpenAI model name |
|
|
536
|
-
| `ANTHROPIC_MODEL` | claude-sonnet-4-
|
|
537
|
-
| `OPENAI_REDACT` | true |
|
|
538
|
-
| `CONFIDENTIAL_KEYWORDS` |
|
|
623
|
+
| `ANTHROPIC_MODEL` | claude-sonnet-4-6 | Anthropic model name (used when `AI_PROVIDER=claude`) |
|
|
624
|
+
| `OPENAI_REDACT` | true | On the CLI, masks the host, most IP addresses, colon-form MACs and serials in the AI scan payload — NOT emails, internal hostnames, Bearer tokens or AWS keys (see **AI Redaction** above) |
|
|
625
|
+
| `CONFIDENTIAL_KEYWORDS` | unset — no keyword scrub | Comma-separated substrings, e.g. `password,token,secret`: on the CLI, while `OPENAI_REDACT` is on, any AI-payload key containing one (any case) has its value replaced with `[REDACTED_HIDDEN]`. Unset, a key such as `password` is not masked for its name (serial-number keys — `serial`, `serialNumber`, `sn` — are masked either way) |
|
|
539
626
|
| `NSAUDITOR_LICENSE_KEY` | — | Pro/Enterprise JWT license key |
|
|
540
|
-
| `COMPLIANCE_GRC_PROVIDER` | — | **Enterprise** — opt-in scan-time GRC push: `vanta`, `drata`, or `secureframe`. Needs `COMPLIANCE_GRC_TOKEN`; optional `COMPLIANCE_GRC_BASE_URL` / `COMPLIANCE_GRC_CONTROL_MAP` / `COMPLIANCE_GRC_REDACTION` (`off`/`hash`/`remove`).
|
|
627
|
+
| `COMPLIANCE_GRC_PROVIDER` | — | **Enterprise** — opt-in scan-time GRC push: `vanta`, `drata`, or `secureframe`. Needs `COMPLIANCE_GRC_TOKEN`; optional `COMPLIANCE_GRC_BASE_URL` / `COMPLIANCE_GRC_CONTROL_MAP` / `COMPLIANCE_GRC_REDACTION` (`off`/`hash`/`remove`, default `off`). Finding content is **NOT redacted by default**: with `off`, a Vanta push carries finding text and `host:port` targets in the clear; `hash` or `remove` scrubs them. Token never serialized. Early-access; live-tenant validation not yet complete. |
|
|
541
628
|
| `SCAN_OUT_PATH` | out/ | Output directory for scan results |
|
|
542
629
|
| `SMB_NULL_SESSION` | false | Allow SMB null session probe |
|
|
630
|
+
| `FTP_CHECK_ANON` | false | Let the FTP check try an anonymous login — without it no scan reports anonymous FTP |
|
|
631
|
+
| `DNS_CHECK_AXFR` / `DNS_AXFR_DOMAIN` | false / — | Let the DNS check try a zone transfer of that zone — without both, `axfrAllowed` stays null (not tested) |
|
|
543
632
|
| `ENABLE_SYN_SCAN` | false | Enable Nmap TCP SYN scanning (requires root) |
|
|
544
633
|
|
|
545
634
|
### Plugin-Specific Timeouts
|
|
@@ -547,9 +636,9 @@ See `references/schemas.md` for complete structures:
|
|
|
547
636
|
| Variable | Default | Plugin |
|
|
548
637
|
|----------|---------|--------|
|
|
549
638
|
| `TLS_SCANNER_TIMEOUT_MS` | 8000 | TLS Scanner |
|
|
550
|
-
| `
|
|
551
|
-
| `
|
|
552
|
-
| `DNS_TIMEOUT_MS` |
|
|
639
|
+
| `HTTP_TIMEOUT_MS` | 6000 | HTTP Probe |
|
|
640
|
+
| `WAPPALYZER_TIMEOUT_MS` | 15000 | Webapp Detector |
|
|
641
|
+
| `DNS_TIMEOUT_MS`, else `DNS_SCANNER_TIMEOUT_MS` | 2000 | DNS Scanner |
|
|
553
642
|
| `OPENSEARCH_SCANNER_TIMEOUT_MS` | 6000 | OpenSearch Scanner |
|
|
554
643
|
|
|
555
644
|
---
|
|
@@ -560,27 +649,31 @@ See `references/schemas.md` for complete structures:
|
|
|
560
649
|
# Install globally
|
|
561
650
|
npm install -g nsauditor-ai
|
|
562
651
|
|
|
563
|
-
# Start MCP server (stdio transport)
|
|
652
|
+
# Start MCP server (stdio transport). Your MCP client starts it itself (configs below); run by hand, it
|
|
653
|
+
# exits at startup unless NSA_MCP_AUTH_KEY holds the value `nsauditor-ai mcp install-key` prints (⚠️ below)
|
|
564
654
|
nsauditor-ai-mcp
|
|
565
655
|
|
|
566
|
-
#
|
|
567
|
-
|
|
656
|
+
# Never `npx nsauditor-ai-mcp`: the server is a bin inside the nsauditor-ai package, and when npx does not
|
|
657
|
+
# find that bin it looks the name up on the npm registry instead — which never starts this server
|
|
568
658
|
```
|
|
569
659
|
|
|
570
660
|
### Agent Integration
|
|
571
661
|
|
|
572
662
|
**Claude Code:**
|
|
573
663
|
```bash
|
|
574
|
-
|
|
664
|
+
nsauditor-ai mcp install-key
|
|
665
|
+
claude mcp add nsauditor-ai --env NSA_MCP_AUTH_KEY=<from: nsauditor-ai mcp install-key> -- nsauditor-ai-mcp
|
|
575
666
|
```
|
|
667
|
+
Run `install-key` once per machine, and use the `NSA_MCP_AUTH_KEY` value in the snippet it prints:
|
|
668
|
+
`keychain:NSA_MCP_AUTH_KEY` when it stored the key in the macOS Keychain, otherwise the literal key.
|
|
576
669
|
|
|
577
|
-
**Claude Desktop** (`claude_desktop_config.json`)
|
|
670
|
+
**Claude Desktop** (`claude_desktop_config.json`) — paste the block `nsauditor-ai mcp install-key` prints, which names node and the server script by absolute path, and add the other variables to its `env`:
|
|
578
671
|
```json
|
|
579
672
|
{
|
|
580
673
|
"mcpServers": {
|
|
581
674
|
"nsauditor-ai": {
|
|
582
|
-
"command": "
|
|
583
|
-
"args": ["-
|
|
675
|
+
"command": "<from: nsauditor-ai mcp install-key — the absolute path to node>",
|
|
676
|
+
"args": ["<from: nsauditor-ai mcp install-key — the absolute path to bin/nsauditor-ai-mcp.mjs>"],
|
|
584
677
|
"env": {
|
|
585
678
|
"NSA_ALLOW_ALL_HOSTS": "1",
|
|
586
679
|
"NSA_MCP_AUTH_KEY": "<from: nsauditor-ai mcp install-key>",
|
|
@@ -591,9 +684,12 @@ claude mcp add nsauditor-ai -- npx nsauditor-ai-mcp
|
|
|
591
684
|
}
|
|
592
685
|
```
|
|
593
686
|
|
|
687
|
+
`NSA_ALLOW_ALL_HOSTS: "1"` lets Claude scan your own network — private addresses such as `192.168.x.x` or `10.x.x.x`. It admits private ranges only (RFC 1918, CGNAT `100.64/10`, `fc00::/7`): the server still refuses loopback, link-local and cloud-metadata addresses in any spelling, whether written as the host or returned for a host name — every answer is checked. Only `1`, `true`, `yes` or `on` turn it on. The check does not pin the answer, so a name whose answer changes between the check and the scan (DNS rebinding) is not caught. `install-key` does not print it, so add it yourself, and remove it if you only scan public hosts.
|
|
688
|
+
|
|
594
689
|
`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
|
|
596
|
-
|
|
690
|
+
another, so the call takes roughly the sum of their times. On one router, a `scan_host` call timed out
|
|
691
|
+
in Claude Desktop on 2026-08-10 and one returned within 138 s on 2026-09-30, so do not promise either
|
|
692
|
+
outcome: a call that times out returned no result — say so, and never report the host as clean.
|
|
597
693
|
|
|
598
694
|
> ⚠️ **`NSA_MCP_AUTH_KEY` is REQUIRED — the server refuses to start without it.** Generate one with
|
|
599
695
|
> `nsauditor-ai mcp install-key`, then put the SAME value in the `env` block above. Without it the MCP
|
|
@@ -621,7 +717,8 @@ Add to your MCP configuration with the same command/args pattern.
|
|
|
621
717
|
|
|
622
718
|
| Error | Cause | Resolution |
|
|
623
719
|
|-------|-------|-----------|
|
|
624
|
-
| SSRF block |
|
|
720
|
+
| SSRF block (`Scanning loopback, link-local, or metadata addresses is not allowed via MCP`) | The target, or any address its name resolves to, is loopback, unspecified (`0.x`, `::`), link-local or a cloud-metadata address — refused with or without `NSA_ALLOW_ALL_HOSTS` — or is private (RFC 1918, CGNAT `100.64/10`, IPv6 `fc00::/7`) while `NSA_ALLOW_ALL_HOSTS` is not `1`, `true`, `yes` or `on`. The message names loopback for a private target too | Private target: set `NSA_ALLOW_ALL_HOSTS=1` in the MCP server env, then fully quit and relaunch the client. A loopback, link-local or metadata target — written so, or reached through what a name resolves to — is refused over MCP with or without it; scan it from the CLI, where `NSA_ALLOW_ALL_HOSTS=1` lifts the whole guard |
|
|
721
|
+
| Unresolvable host (`Host could not be resolved via MCP: <host>`) | The name does not resolve — with or without `NSA_ALLOW_ALL_HOSTS` — or the string is not one host: a CIDR or URL-shaped string (`10.0.0.0/8`, `host:80`) is refused this way | Check the spelling; pass one host name or IP address; scan a range from the CLI (`--host <CIDR>`) |
|
|
625
722
|
| License gate (`🔒`) | Pro/Enterprise tool on CE | Upgrade license or use CE alternative |
|
|
626
723
|
| 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 |
|
|
627
724
|
| No DNS banner | Provider blocks CHAOS/TXT queries | Expected; not all DNS servers expose version |
|