A clean, linear getting-started path for new NSAuditor AI Enterprise customers: install → activate → configure → scan → read the results. Ten steps, plus an optional Pro add-on and the Claude Desktop / MCP workflow. Everything runs on your machine, and every outbound path the product can take is enumerated in its published egress register, so the claim is one you can audit rather than one you have to trust.
Written for the current shipped product, EE 0.40.1, which requires
CE ≥ 0.2.43 — install the trio in Step 2 and you get the matching pair.
New in 0.34.0 and set up between Steps 6 and 7:
exploit intelligence — CISA KEV + FIRST EPSS,
which reorders the finding queue so a known-exploited MEDIUM outranks an unexploited CRITICAL.
RFC 3161 trusted timestamping is opt-in via
NSAUDITOR_TSA_URL — never a default —
and each compliance artifact then carries a .tsr sidecar your auditor verifies offline with stock
openssl, against a Time-Stamp Authority you choose, with none of our software in the path.
New in 0.36.0: your report checks the suppression signatures it renders against recorded key material, for
approvers whose registry entry carries the public key beside its fingerprint. A missing verdict means
not checked, never failed — set the approvals up here, and Step 9
shows you how to read the verdict.
After buying NSAuditor AI Enterprise from nsauditor.com/ai/enterprise, your confirmation email contains two things you'll need below:
• your Enterprise license key — enterprise_eyJhbGciOiJFUzI1NiIs...
• your npm access token — npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
(read-only; @nsasoft/nsauditor-ai-ee is a private, restricted npm package).
First, register to receive your license key. AWS bills you, but it doesn't hand us your email —
so after subscribing on the
AWS Marketplace listing,
go to nsauditor.com/ai/marketplace/register
and enter your email, your AWS account ID, and your Agreement ID (agmt-…, shown in
AWS Console → AWS Marketplace → Manage subscriptions). Your ES256-signed license key is then emailed to you.
(The Usage Instructions on the listing carry the same steps.)
Your delivery channel is the Docker container image, not npm — the emailed key comes with the
docker login / docker pull / docker run commands instead of an npm token,
and the image already bundles the full platform (CE + Enterprise package).
Skip steps 0–3 and 5 below — run the container with your key instead:
docker run --rm -e NSAUDITOR_LICENSE_KEY="enterprise_eyJ..." <image> license --status.
Steps 4 (cloud credentials — pass them as -e vars or a mounted --env file),
6–7 (your first scan and --aws-region scoping), and 9 (reading the results) apply identically
inside the container. Billing, renewal, and cancellation for Marketplace orders are managed in your
AWS account (see the EULA's AWS Marketplace Addendum) — your license key still verifies fully offline.
Enterprise add-on (new in EE 0.38.0): Establish evidence-pack authorship — compliance sign-pack / verify-pack
Isolated networks (new in EE 0.37.0): Install on an air-gapped host — carry the package and the CVE data in
Enterprise add-on (new in EE 0.36.0): Sign and verify suppression approvals
Pro add-on (new in EE 0.34.0): Set up exploit intelligence — CISA KEV + FIRST EPSS
NSAuditor AI runs on Node.js 20 LTS or newer. Download
the installer from the official Node.js Downloads
page, choose the LTS build (not "Current" — LTS is the
stable line), and run the installer that matches your OS (Windows .msi / macOS
.pkg).
$ node --version # v20.x or newer $ npm --version
@nsasoft/nsauditor-ai-ee is a private (restricted)
package. Configure the read-token from your license email so npm can download it.
# Global: set the auth token for the npm registry $ npm config set //registry.npmjs.org/:_authToken npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Or, scoped to your home ~/.npmrc $ echo "//registry.npmjs.org/:_authToken=npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" >> ~/.npmrc
Install all three packages: the free Community Edition runtime, the agent skill (for Claude Desktop / Claude Code), and the Enterprise package — your 28 Enterprise plugins (27 cloud auditors plus 1023 Zero Trust Assessment, which scores a network-host scan) and seven compliance frameworks.
$ npm install -g nsauditor-ai@latest \ nsauditor-ai-agent-skill@latest \ @nsasoft/nsauditor-ai-ee@latest
1 · Re-check any suppression rule that matches the evidence-gap finding by title. EE 0.32.9 changed the title of the evidence-gap finding. A suppression rule written against the old text stops matching, so those findings resurface rather than stay hidden. That is the safe direction — nothing is silently suppressed — but the change itself is silent: no error, no warning, the rule simply goes inert. Re-point any rule keyed to the old wording.
2 · Re-scan; do not re-process a scan captured before 0.32.9. An archived scan taken on an earlier build was captured before the fail-closed evidence-gap behavior existed, so re-processing it cannot reconstruct what a cloud that failed to start would now disclose. The engine warns when it re-processes such a scan. Run the scan again against the live account instead of re-rendering the old capture.
Why it matters: before 0.32.9, when a cloud plugin could not start — its optional SDK absent, its credentials unusable — it refused to report, and that refusal evaporated one layer up. The compliance report came out byte-identical to one where the scanner ran and found nothing: ten controls read PASS, no violation, no warning. The dangerous shape is ordinary — AWS and GCP scan for real, Azure's SDK is absent, and the combined pack reads as a clean three-cloud audit. Now every in-scope control of a cloud that could not be scanned carries a fail-closed evidence gap. Expect gaps where you previously saw passes; that is the corrected reading.
3 · Expect four more out-of-scope rows in your next SOC 2 report. EE 0.32.11 enumerates the SOC 2 matrix in full at 10 covered / 4 partial / 37 out of scope = 51. CC7.4, CC7.5, A1.1 and A1.3 had appeared nowhere in the mapping data — silently non-enumerated, which is not the same thing as out-of-scope-with-a-reason. Each now renders with an architectural reason and the operator-side evidence that closes it. No control changed status and no routing changed: covered stays 10, partial stays 4, and every existing control-id membership is identical. The other six matrices are unchanged.
One command — no shell-rc edits. The CLI verifies the JWT signature before
persisting, and stores the key in the macOS Keychain (or ~/.nsauditor/.env mode
0600 on Linux/Windows).
$ nsauditor-ai license install enterprise_eyJhbGciOiJFUzI1NiIs... ✓ Enterprise license installed Stored at: macOS Keychain (service=nsauditor-ai) Org: you@example.com Seats: 5 Expires: 2027-04-04T...
An environment variable also works and takes highest priority in the multi-source loader:
export NSAUDITOR_LICENSE_KEY=enterprise_eyJ...
If you ever hit a license_id_mismatch on macOS, clear both
~/.nsauditor/license-state.json and the Keychain entry
NSAUDITOR_LICENSE_ID (Keychain wins on read). On Linux/Windows it is file-only.
Create a dotenv file with your AI provider key and the cloud credentials for the account(s)
you want to audit. Everything stays on your machine — nothing is sent to NSAuditor. Keep
one .env per account (e.g. ~/envs/dev.env,
~/envs/prod.env) and select it per scan with --env (Step 6).
# ── AI provider (used for the optional AI analysis layer) ── AI_ENABLED=true AI_PROVIDER=claude # openai | claude | ollama ANTHROPIC_API_KEY=sk-ant-... # or keychain:ANTHROPIC_API_KEY on macOS — your key, stays local ANTHROPIC_MODEL=claude-sonnet-4-6 # ── Which cloud(s) this file audits ── CLOUD_PROVIDER=aws,gcp,azure # ── AWS ── AWS_ACCOUNT_ID= AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 # ── Azure ── AZURE_CLIENT_ID= AZURE_CLIENT_SECRET= AZURE_TENANT_ID= AZURE_SUBSCRIPTION_ID= # ── GCP (Application Default Credentials) ── GOOGLE_CLOUD_NUMBER= GOOGLE_CLOUD_PROJECT_ID= GOOGLE_APPLICATION_CREDENTIALS=/Users/myuser/.config/gcloud/application_default_credentials.json GOOGLE_IMPERSONATE_SERVICE_ACCOUNT=your@project-id
NSAuditor AI performs read-only auditing — it reads configuration and metadata only and never needs create, write, modify, or delete permissions. Always supply read-only, least-privilege credentials for the account(s) you audit:
ReadOnlyAccess or SecurityAudit managed policyReader roleroles/viewerRead-only scoping guarantees an audit cannot change your environment. Supplying credentials with write or other state-changing permissions is unnecessary and is entirely at your own risk. You are responsible for provisioning, scoping, rotating, and revoking these credentials — see EULA §5.5.
$ nsauditor-ai license --status ✓ Enterprise license active | Org: you@example.com | Seats: 5 | Expires: 2027-04-04
The headline use case is a cloud audit: point NSAuditor at a cloud account and get one evidence pack mapped across the compliance frameworks you ask for.
# Scan ALL THREE clouds in one run — comma-separated sentinels (CE 0.2.17+). # --plugins all auto-scopes each cloud to only its plugins; one out/ subfolder per cloud. $ nsauditor-ai scan --host aws,gcp,azure --env ~/envs/clouds.env --plugins all --compliance all --out out # …or one cloud at a time, one dotenv file per account (credentials load for THIS scan only) $ nsauditor-ai scan --host aws --env ~/envs/dev.env --plugins all --compliance soc2 --out out/aws-dev $ nsauditor-ai scan --host aws --env ~/envs/prod.env --plugins all --compliance soc2 --out out/aws-prod # Or a named profile from ~/.aws/credentials (no .env needed) $ nsauditor-ai scan --host aws --aws-profile prod --plugins all --compliance soc2 --out out/aws-prod # GCP / Azure per-account via --env (key-file path / service-principal vars live in the file) $ nsauditor-ai scan --host gcp --env ~/envs/gcp-prod.env --plugins 1021 --compliance soc2,cis-v8 --out out/gcp-prod $ nsauditor-ai scan --host azure --env ~/envs/azure-prod.env --plugins 1022 --compliance soc2 --out out/azure-prod
--host aws,gcp,azure scans one or more clouds in a single run (comma-separated; --host aws for just one). With --plugins all each cloud auto-scopes to only its plugins (other clouds + non-cloud plugins are skipped and logged). Don't write aws|gcp|azure with pipe characters — your shell treats | as a pipe.--compliance takes a CSV of any of the eight frameworks: soc2,hipaa,nist-csf,pci-dss,iso-27001,cis-v8,gdpr,nist-800-171 (gdpr emits the GDPR Article 32 Security-of-Processing infrastructure substrate — Art. 32 only, not GDPR compliance).COMPLIANCE_GRC_PROVIDER=vanta (or drata / secureframe) + COMPLIANCE_GRC_TOKEN and the scan maps its findings to your Vanta, Drata, or Secureframe workspace and pushes them at scan time — opt-in, early-access, Zero-Data-Exfiltration by default, token never serialized. See the GRC Connectors guide for the full setup.--env file is a hard error (fail-fast, never a silent skip).--out <dir> writes into the directory you name. In CE 0.2.34 a directory whose name contains a dot (e.g. --out out/ee-0.32.9) is correctly treated as a directory; earlier builds read the dot as a file extension and wrote the artifacts into the parent directory instead.
CISA KEV + FIRST EPSS
On the Pro tier and above (every Enterprise license includes it), findings that
carry CVEs are joined by CVE ID against a local CISA KEV catalog and a local
FIRST EPSS scores file, banded KNOWN_EXPLOITED / ELEVATED / BASELINE, and the
finding queue is reordered exploit-first — a KEV-listed MEDIUM outranks an unexploited
CRITICAL, with the reason attached to every promoted finding: the KEV flag, the EPSS score with its percentile,
the matched CVE ids, and the store's own as-of date. It is off until you configure it,
and no feed data ships with the product — both stores are public files you download and refresh yourself.
# 1 · Download the two public feeds (no account needed for either) $ mkdir -p ~/.nsauditor/feeds $ curl -fsSL https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json -o ~/.nsauditor/feeds/kev.json $ curl -fsSL https://epss.empiricalsecurity.com/epss_scores-current.csv.gz | gunzip > ~/.nsauditor/feeds/epss.csv # 2 · Point the scanner at them (add both lines to your shell profile to persist) $ export NSAUDITOR_EXPLOIT_KEV_STORE=~/.nsauditor/feeds/kev.json $ export NSAUDITOR_EXPLOIT_EPSS_STORE=~/.nsauditor/feeds/epss.csv # 3 · Scan as usual — findings that carry CVEs now arrive banded and ordered exploit-first $ nsauditor-ai scan --host 10.0.0.0/24 --plugins all --out out/lan
~ expands only in a shell. In a --env file or in Claude Desktop’s MCP env config (step 8), write the absolute path instead — e.g. /Users/you/.nsauditor/feeds/kev.json. A path the scanner cannot read is banner-reported as no-store, never as “not exploited”.signed approvalsA suppression is you telling the report that a finding is an accepted risk or a false positive. Suppressions without a signature are first-class and always have been. What 0.36.0 adds is that every compliance report cryptographically verifies each suppression signature it renders, for approvers whose registry entry carries key material — so an auditor can check that an approval came from the person it names, instead of taking a string in a file at its word. This is off until you set it up, it is CLI-only (the MCP surface does not reach these commands), and the private key never leaves your machine. Step 9 shows you how to read the verdict this produces.
# 1 · Create an approval keypair. Private half is written 0600 and stays here. # It prints an identity-registry member you can paste as-is. $ nsauditor-ai compliance keygen --key ~/.nsauditor/approver.pem \ --approver "Ann Approver" --email ann@example.com --role CISO --team Security # 2 · Paste that member into your identity registry and point the scanner at it. # KEEP THE publicKey FIELD — the fingerprint alone identifies an approver, but only # the key material lets a report CHECK their signature. $ export NSAUDITOR_IDENTITY_REGISTRY=~/.nsauditor/identity_registry.json # 3 · Record an approval. It is signed because NSAUDITOR_SIGNING_KEY names your key. $ export NSAUDITOR_SIGNING_KEY=~/.nsauditor/approver.pem $ nsauditor-ai compliance suppress --suppressions ./audit-out/suppressions.json \ --source auth_agent --title-pattern "SSH password authentication enabled" \ --status accepted_risk --rationale "WAF compensating control at the perimeter" \ --approver "Ann Approver" --attestation-level approver # → wrote ./audit-out/suppressions.json — supp-ff78d65c-b96 (accepted_risk) # signed: ed25519/local at level approver, checked for approvers whose registry entry carries key material # 4 · Scan. The approval is picked up and its signature checked, for approvers whose registry entry carries key material. $ nsauditor-ai scan --host aws --compliance soc2 --out ./audit-out # Review every approval with expiry status, or re-approve before expiry: $ nsauditor-ai compliance review --history ./audit-out $ nsauditor-ai compliance renew --suppressions ./audit-out/suppressions.json \ --id supp-ff78d65c-b96 --rationale "quarterly re-review" --approver "Ann Approver"
suppressions.json at your --out base — the directory you pass, not the
timestamped <host>_<time>/ folder created inside it during the run. Set
NSAUDITOR_SUPPRESSIONS to override with an explicit path; an absolute path is honoured
verbatim and a relative one resolves against your working directory, never against the folder
the scan invents.keygen refuses to overwrite an existing key. Regenerating over a signing key destroys
the ability to verify every signature it ever made, and nothing tells you at the time — your registry still
names the old fingerprint, so it surfaces later as public_key_mismatch on archived evidence that
was correct when written. Pass --force only if you mean it, then re-register the new fingerprint.renew on a signed approval invalidates its signature, and says so. The expiry and the
renewal record live inside the signed payload, so the record afterwards reads
signature does not match payload — indistinguishable from real tampering. Re-approve with signing
to restore it.signed — not checked by this report, which records that no check ran and never that one failed.
Every field registry starts this way; adding publicKey per approver is the migration.awskms: key references are refused in this release — KMS-held signing is built but has not
been exercised against a live key, so it is not reachable here. Local keys and
keychain:LABEL references work.compliance sign-pack / verify-pack
A pack already carried SHA-256 sidecars, which prove bytes were not altered. Neither says
who produced it. compliance sign-pack signs the chain-of-custody
envelope with an operator-held Ed25519 key at an approval station, so the
scanning fleet stays keyless. CLI-only, and off until you set it up.
Scope, because it decides what the signature is worth to an assessor. A verified signature proves the holder of a key asserted authorship of one framework’s envelope and the four artifacts it enumerates — not the directory, and not the pack. The key is yours, so authorship is relative to your own key custody and is never a vendor attestation. It is not proof the scan ran, and not proof the findings are true.
# the operator-held signing key — generated outside any container, never on a scanner host
openssl genpkey -algorithm ed25519 -out nsauditor-signing.pem
chmod 600 nsauditor-signing.pem
openssl pkey -in nsauditor-signing.pem -pubout -out nsauditor-signing.pub
# the registry keys on the SPKI-DER fingerprint — first 24 hex of its SHA-256
echo "sha256:$(openssl pkey -pubin -in nsauditor-signing.pub -outform DER \
| openssl dgst -sha256 -binary | xxd -p -c 256 | cut -c1-24)"
Copy the shipped template (data/compliance/identity_registry.json) and add the fingerprint, the
public key and a bounded validity window. Rotation is re-registering with a new
window, and that window is what turns signed_after_revocation / signed_outside_validity
into audit evidence.
{
"schemaVersion": 1,
"members": [{
"displayName": "Release Signing Authority",
"email": "security@example.com",
"role": "Release Signing Authority",
"publicKeyId": "sha256:975a2fc435697025c2765ed7",
"publicKey": "-----BEGIN PUBLIC KEY-----\n…\n-----END PUBLIC KEY-----\n",
"approverFor": ["soc2"],
"attestationLevel": "approver",
"validFrom": "2026-01-01T00:00:00.000Z",
"validUntil": "2027-12-31T23:59:59.000Z",
"revokedAt": null
}]
}
⚠️ Malformed shapes are refused at load, each with exit 2 — “could not
measure” rather than a verdict: a missing schemaVersion, a member without
email, a member without an approverFor array. Key material under any name other than
publicKey ends the same way by a different route: the registry loads, the member counts as having
no key material, and the run reports that nothing was checked — exit 2
again. Exit 2 is never a pass.
NSAUDITOR_SIGNING_KEY=./nsauditor-signing.pem \
nsauditor-ai compliance sign-pack \
--manifest ./out/<scan>/scan_chain_of_custody_soc2.json \
--approver "Release Signing Authority" \
--registry ./identity_registry.json
Two files are written beside the pack: scan_pack_signature_soc2.json (the record) and
scan_pack_signature_soc2.payload.json — the exact bytes that were
signed. The payload ships so an auditor never has to reproduce a canonicalisation.
# through the identity registry — checks WHO, plus revocation and validity AS AT SIGNING TIME
nsauditor-ai compliance verify-pack --manifest ./out/<scan>/scan_chain_of_custody_soc2.json \
--registry ./identity_registry.json
# with a bare public key — verifies the SIGNATURE only, and says so in its own output
nsauditor-ai compliance verify-pack --manifest ./out/<scan>/scan_chain_of_custody_soc2.json \
--public-key ./nsauditor-signing.pub
Supplying both is refused with exit 2, deliberately: a silent precedence rule would let the output name an anchor that was never consulted. Exit 0 verified · 1 a violation · 2 the run could not measure — and the third is never a failure.
A clean run prints the scope bound too, on success as well as on failure:
identity: OK — resolved through the identity registry … revocation and validity checked as at signing time.
signature: VERIFIED — soc2 / <scanId>, identity model not declared
artifacts: 4 of 4 re-hashed and matching
The trailing identity model not declared is expected, not a warning about your setup: the
signature record itself asserts no attestation level, and the verifier will not promote a registry attribute into
a claim the record never made — who signed comes from the identity: line above it.
Because a signature alone would authenticate a manifest whose artifact claims nothing had ever checked. Edit one byte of a covered report — without changing its length — and you get:
signature: VERIFIED ← the signature is genuinely fine
artifacts: ARTIFACT_HASH_MISMATCH — artifact(s) do not match their recorded sha256: scan_compliance_soc2.md
exit 1
A verifier that stopped at the signature would have called that pack clean. Tamper with the manifest instead and
the verdict is MANIFEST_DIGEST_MISMATCH, with both digests printed — and it accuses nobody, because
a manifest legitimately regenerated after signing hashes differently by construction.
# 1 — read the digest from the PAYLOAD, never from the record (the record is unauthenticated)
jq -r .manifestSha256 scan_pack_signature_soc2.payload.json
# 2 — hash the manifest on disk and compare
shasum -a 256 scan_chain_of_custody_soc2.json
# 3 — verify the signature over the payload bytes
jq -r .value scan_pack_signature_soc2.json | base64 -d > sig.bin
openssl pkeyutl -verify -pubin -inkey nsauditor-signing.pub -rawin \
-in scan_pack_signature_soc2.payload.json -sigfile sig.bin
# → Signature Verified Successfully
Step 1 reads the payload, not the record, and that ordering is the point: an attacker who substitutes the manifest could also rewrite the digest it is compared against if you read the record.
--aws-region
By default an AWS scan covers a single region (AWS_REGION,
else us-east-1). The --aws-region <one|csv|all> flag controls
which regions the regional auditors cover — and each now audits
every in-scope region, with genuine per-region fan-out (security
groups, EC2, RDS, KMS, Lambda, Secrets Manager, DynamoDB, CodePipeline/CodeBuild, Backup, SQS/SNS,
VPC endpoints, ElastiCache, SES, Inspector/GuardDuty, and CloudTrail).
# A single region $ nsauditor-ai scan --host aws --plugins all --compliance soc2 --aws-region us-east-1 # A comma-separated list of regions $ nsauditor-ai scan --host aws --plugins all --compliance soc2 \ --aws-region us-east-1,eu-west-1,ap-southeast-2 # Every region enabled on the account (DescribeRegions; static-list fallback on AccessDenied) $ nsauditor-ai scan --host aws --plugins all --compliance soc2 --aws-region all
What a scoped run looks like, end to end:
$ nsauditor-ai scan --host aws --plugins all --compliance soc2 \ --aws-region us-east-1,eu-west-1,ap-southeast-2 --out out/aws-prod [region] scope = flag-list · 3 regions requested → resolving… [region] scanning us-east-1, eu-west-1, ap-southeast-2 (regional plugins fan out per-region) [plugin] AWS EC2 SG Perimeter Auditor (1170) ......... 3 regions · 5 findings [plugin] AWS RDS Auditor (1140) ...................... 3 regions · 2 findings [plugin] AWS IAM Deep Auditor (1030) ................. global · audited once [plugin] AWS S3 Security Auditor (1020) .............. per-bucket region resolved · 6 findings ✓ scanScope: regionsScanned=[us-east-1, eu-west-1, ap-southeast-2] regionsWithError=[]
--aws-region flag › AWS_REGION (shell / --env file) › single-region default.
AWS_REGION--aws-region all for full coverage.
NSA_AWS_REGION_ALLOW_UNKNOWN=1 to permit a brand-new region); an AWS_REGION-derived value warns and proceeds.
--aws-region. The S3 auditors resolve each bucket's own region and skip + disclose buckets outside the scoped set — closing latent cross-region false-cleans.
> Incomplete region coverage — 16 enabled region(s) not scanned (eu-west-1, ap-south-1, …). Re-run with --aws-region all (or set AWS_REGION) for full coverage.
Run audits conversationally from Claude Desktop — "Audit my AWS account" — via the MCP server bundled with the package.
In Claude Desktop go to Customize → Skills, click +,
choose Create skill → Upload a skill, and upload
SKILL.md from the @nsasoft/nsauditor-ai-ee package
(SKILL.md on GitHub).
macOS example, using Keychain references:
NSA_ENV_FILE=~/envs/dev.env MCP_TIMEOUT=180000 AI_PROVIDER=claude ANTHROPIC_API_KEY=keychain:ANTHROPIC_API_KEY NSA_ALLOW_ALL_HOSTS=1 PLUGIN_TIMEOUT_MS=90000 CLOUD_PLUGIN_TIMEOUT_MS=45000 NSA_MCP_AUTH_KEY=keychain:NSA_MCP_AUTH_KEY NSAUDITOR_LICENSE_KEY=keychain:NSAUDITOR_LICENSE_KEY
Claude Desktop enforces a hard ~60s per-tool-call limit that MCP_TIMEOUT
does not extend (that knob only governs server startup). Keep
CLOUD_PLUGIN_TIMEOUT_MS under ~60s (e.g. 45000) so a slow
plugin returns partial-with-disclosure rather than a hard timeout.
Say "Audit my AWS account" (one cloud) or "Audit my AWS and Azure accounts"
(several). For region scoping, the MCP scan_cloud tool takes the same scope as a
regions argument:
regions → audits only the server-configured AWS_REGION (one region; a single tool-call stays within Desktop's timeout). This is the default for a plain "audit my AWS account".["us-east-1","eu-west-1"]).["all"] call that could time out. You do not need to raise any timeout for this.
Everything above assumes the host can reach a registry. If yours cannot, the install and the
vulnerability data both have to be carried in. One condition travels with this path:
the bundle is a restricted distribution rather than a public npm install.
It is not architecture-restricted. Both arches are exercised for this release
rather than inherited from an earlier one: native aarch64, and linux/amd64 in a
container run with --network none — no interface, and DNS does not resolve. (The published
container image is amd64 only — a different delivery vehicle from this bundle.)
The air-gap bundle is a separate, restricted package carrying dependency-complete tarballs for both editions, an install script and SHA-256 checksums. Authenticate with the download token from your purchase email, then fetch it:
npm pack @nsasoft/nsauditor-ai-ee-airgap@0.39.0
tar xzf nsasoft-nsauditor-ai-ee-airgap-0.39.0.tgz
Copy the extracted directory to the isolated host and run its script. It verifies the carried checksums before installing anything, installs Community Edition first (Enterprise declares a peer dependency on it), and forces every install offline:
./install.sh
nsauditor-ai license --plugins
A host with no sha256sum or shasum is refused rather than installed onto —
unverified bytes are not installed silently.
What is checked before this bundle ships. Each release re-builds the bundle and runs a
delivery gate against those exact tarballs: it asserts that every declared production
dependency resolves from the carried closure (43 of 43 for EE 0.40.1), that the plugin census
loads (28 Enterprise plugins), that a store-backed scan returns findings from carried CVE data,
and that the run makes zero network attempts. The gate never reads npm’s exit
status, because that is measured non-evidence here: every production dependency is an
optionalDependency, and a NIC-down install of the unvendored package exits
0 while installing almost nothing. Verify the delivery, not the installer.
The installer’s exit code is the one thing you should not trust here, and the reason is
structural rather than a bug: every production dependency is an optionalDependency, and npm
skips an unfetchable optional silently. On an isolated host, an install that fetched
nothing still exits 0 and still prints a cheerful summary line. Two commands tell you what
actually landed:
# 1. every declared production dependency resolves from the carried closure
node -e "const p=require('@nsasoft/nsauditor-ai-ee/package.json');
const d=Object.keys(p.dependencies||{}).concat(Object.keys(p.optionalDependencies||{}));
let ok=0; for (const m of d) { try { require.resolve(m); ok++; } catch {} }
console.log(ok + '/' + d.length + ' resolved');"
# 2. the plugin census loads, and the Enterprise tier is active
nsauditor-ai license --plugins
For EE 0.40.1 the first command must print 43/43, and the second must report the Enterprise
plugins active (28 Enterprise, 55 in total). A partial number is a failed delivery that npm
reported as a success. As a deliberate control, the same procedure run against the ordinary
(non-bundled) package on an isolated host resolves 0 of 43 — while npm still exits
0.
No CVE, KEV or EPSS data ships with the product. On a connected host, download the NVD feeds you want and bundle them; optionally carry your own CISA KEV catalogue and FIRST EPSS scores in the same archive:
nsauditor-ai feed bundle --from ./nvd-downloads --out feeds.json.gz \
--kev ./known_exploited_vulnerabilities.json \
--epss ./epss_scores.csv.gz
Carry feeds.json.gz across and import it on the isolated host:
# imports the feeds you downloaded, from a bundle you carried — restricted distribution
nsauditor-ai feed import --file feeds.json.gz --extras-dir ./stores
Import prints the environment variables to set for any carried KEV/EPSS files, and names why it skipped records. About a quarter of a real NVD year file is skipped by design — withdrawn CVEs and entries with no CPE match data. That is not data loss. Malformed records are a different signal and mean re-download.
export NSAUDITOR_OFFLINE_ONLY=1
export NSAUDITOR_EXPLOIT_KEV_STORE=./stores/known_exploited_vulnerabilities.json
export NSAUDITOR_EXPLOIT_EPSS_STORE=./stores/epss_scores.csv.gz
nsauditor-ai scan --host aws --env ./org.env --compliance soc2 --out ./out
NSAUDITOR_OFFLINE_ONLY=1 refuses to start if an outbound path is also configured, which
rules out the opt-in RFC 3161 timestamping path in the enclave — that setting makes an outbound call to the
authority you name, and has no default.
A store that cannot answer emits a coverage gap rather than a silent clean.
⚠️ A carried bundle is integrity-checked, not authenticated. The recorded SHA-256 detects a file altered in transit, but it travels inside the archive it covers, so it cannot establish who built it. Treat a bundle as you would any media crossing into an enclave: obtain it over a channel you trust, and check it against the checksums you were given separately.
The bundle's dependency closure is as of its build date; each release rebuilds and re-audits it, and
enclaves update by carrying the new bundle. One optional dependency (mdns) is a native
module that cannot compile without network access — it is not required, and mDNS discovery falls back
to a pure-JavaScript implementation.
--out directory, one timestamped folder per scan (e.g. aws_20260524_091331/), with the per-framework reports plus SHA-256 chain-of-custody sidecars.
CRITICAL / HIGH / MEDIUM / LOW / INFO; the summary rolls them up per provider.
scanScope block (and the incomplete-coverage advisory) to confirm which regions were actually scanned. Don't infer "all regions" from GuardDuty/Inspector findings — those enumerate regions internally regardless of scope.