NSAuditor AI EE produces a Type-I-friendly pre-audit gap report mapped to the AICPA Trust Services Criteria 2017 (with 2022 points of focus). SHA-256 chain-of-custody sidecars, cover-page Scope Attestation, suppression workflow, and GRC-ready evidence JSON with scan-time push connectors for Vanta, Drata, and Secureframe — out of the box.
✓ 10 controls fully covered⚠ 4 partial↑ Type I & Type II⇄ Vanta + Drata + Secureframe pushLatest: EE 0.37.0 (2026-08-16) — the air-gap release: feed bundle and feed import carry NVD feed data, and optionally your own CISA KEV and FIRST EPSS files, onto a network that cannot fetch them. Requires CE 0.2.42 or newer, and the SOC 2 matrix is unchanged
CURRENT · EE 0.37.0 · 2026-08-16EE 0.37.0 · CE 0.2.42 · agent-skill 0.2.40
EE 0.37.0 (2026-08-16) is the current release — vulnerability data can now be carried onto a network that has no way to fetch it. nsauditor-ai feed bundle merges the NVD feed files you downloaded on a connected host into one portable archive; feed import reads it into the offline CVE store on the far side and names why it skipped records — withdrawn CVEs and entries with no CPE data are expected, and are not data loss. Optional --kev / --epss carry your own CISA KEV and FIRST EPSS downloads inside the same archive, validated on the connected host where a bad file can still be replaced — no exploit data ships with this product. Each carried file records a SHA-256 that import verifies, so a file altered in transit is detected. Air-gapped delivery now ships as a dependency-complete bundle with an install script and checksums — restricted distribution, amd64 only. No arm64 image is published. EE 0.37.0 requires CE ≥ 0.2.42 — the floor is raised this cycle, because the new feed commands are routed from Community Edition and an older CE would build an incomplete archive without saying so. Paired CE 0.2.42 + agent-skill 0.2.40.
Prior — EE 0.36.0 (2026-08-13) was the verification release. A compliance report now cryptographically checks the suppression signatures it renders, for approvers whose registry entry carries key material, and the verdict names the exact signature bytes it checked. That is the difference between showing an auditor that an accepted risk carries a named approver and showing which bytes carry that approval. Two axes travel with the verdict — verified answers whether the suppression should stand, cryptoValid answers whether those bytes came from the named key — and they diverge on a revoked key, which is what makes signing after revocation a cryptographic finding rather than an operator-editable string. A tampered record renders “signature FAILED verification”. The condition is not decoration: every identity registry in the field today is fingerprint-only, so a missing verdict means NOT CHECKED and never FAILED — the report says “signed — not checked by this report”, and a report advisory names how many registered approvers are still awaiting material and what to paste. An engine fault in the identity phase now fails that framework’s report loudly instead of rendering a degraded section that told the auditor to restore a registry that was fine — a disclosed failure attributed to the wrong party is not a disclosure. The scan, the other frameworks and the findings artifacts are untouched. Matrix-neutral — 28 Enterprise plugins (27 of them cloud auditors), 55 overall, seven frameworks, and the SOC 2 matrix UNCHANGED at 10 covered / 4 partial / 37 OOS = 51. Paired CE 0.2.41 + agent-skill 0.2.39.
Prior: EE 0.35.0 (2026-08-12) — the approval surface, and the writing half of this one. Suppression approvals got a CLI (compliance suppress | review | renew | keygen) and NSAUDITOR_SIGNING_KEY became a setting that changes the artifact, so suppress signs the approval it writes when the variable names a local Ed25519 key, and 0.36.0 is the half that reads that approval back, for approvers whose registry entry carries key material. The entry points these releases rely on live in Community Edition, so EE 0.36.0 requires CE ≥ 0.2.40 — unchanged from the previous release, because nothing in this cycle needs new Community Edition code.
Prior: EE 0.34.0 — exploit-first triage. Severity ranks how bad a vulnerability would be if exploited; it never tells you whether anyone is exploiting it. EE 0.34.0 answers that at scan time. Every finding carrying a CVE is joined by CVE ID against the CISA Known Exploited Vulnerabilities catalog and FIRST EPSS exploitation-probability scores, and lands in one of three bands — KNOWN_EXPLOITED, ELEVATED or BASELINE. The queue is ordered exploit-first, so a KEV-listed MEDIUM outranks an unexploited CRITICAL, and the evidence travels with the finding: the KEV flag, the EPSS score with its percentile, the CVE ids that matched and the publication date of the catalog they were matched against — so an assessor can see why a finding was ranked where it was. Both catalogs are free, public and operator-supplied, and the join runs entirely on your machine: point the Pro tier at the KEV and EPSS files you already trust, and no CVE, host or finding leaves your network to obtain the ranking. riskScore is untouched — exploitPriority is a new axis beside it.
It builds on EE 0.33.1, which stated auditor-verifiable proof in every framework report. All seven auditor-shaped reports say the same thing about evidence integrity: RFC 3161 trusted timestamping is opt-in via NSAUDITOR_TSA_URL, pointed at a Time-Stamp Authority you choose, and every compliance artifact then carries a .tsr sidecar your auditor verifies offline with stock openssl — against that third party, with none of our software in the path. Opt-in with no default, ever, so an air-gapped environment simply leaves it unset. Verified end to end on 2026-08-07 against a real public Time-Stamp Authority through the published binaries.
Zero Data Exfiltration, rebuilt as a positive register. The claim used to be a denial; it is now an enumeration of 17 outbound paths, each named with what triggers it and how to switch it off, so an auditor reads what the process does contact rather than accepting “nothing” on faith. RFC 3161 trusted timestamping is now opt-in via NSAUDITOR_TSA_URL and was verified against a real timestamp authority on 2026-08-07 — opt-in, not a default, and it is one of those outbound paths. Ed25519 suppression signing has been reachable as of EE 0.35.0, and its verification gate has since run against published bytes, for approvers whose registry entry carries key material — compliance suppress signs the approval it writes when NSAUDITOR_SIGNING_KEY names a local signing key, and the report reads that approval back and renders a per-record verdict. Signature records now carry algorithm and backend frozen at the moment of signing rather than re-derived later from the current configuration.
That release was matrix-neutral — all seven coverage matrices UNCHANGED, plugin count UNCHANGED at 28 Enterprise plugins (27 of them cloud auditors), 55 overall. The SOC 2 matrix is UNCHANGED at 10 covered / 4 partial / 37 OOS = 51. Paired CE 0.2.37 + agent-skill 0.2.35.
Prior: EE 0.32.11 (2026-08-05) — the release gate that is supposed to tell us what a customer actually installs had been auditing the maintainer’s development tree and calling it the production closure.
1. The gate now measures the shipped artifact. It packs the tarball, installs it the way a customer does, and audits that — and it refuses to report clean until it has proved an advisory database actually answered. A gate that could not measure now says so instead of saying “clean”.
2. Why the difference is not a rounding error. The development tree carries 25 advisories, 8 of them HIGH. The closure a customer installs carries 6, none HIGH. Across 26 advisory packages the two lists share five — and zero high-severity ones. Every one of those eight highs was development-only. This is the shape that matters to an auditor asking what your scanner is running: a wrong tree does not produce an obviously wrong number, it produces a number that reads exactly like the right one.
Also in that release: the SOC 2 matrix was enumerated in full — 10 covered / 4 partial / 37 out of scope = 51, the complete AICPA TSC 2017 universe at this file’s granularity. This is enumeration completeness, not a coverage change: no control changed status and no routing changed; criteria that had been silently absent from the enumeration are now stated out of scope with a reason. Earlier release notes on this page report the same coverage against the older 47-unit enumeration. The other six matrices are unchanged. The Type I vs Type II documentation now says, mechanism by mechanism, which parts are reachable from a shipped entry point and which are not.
Verified on the published bytes, not the source tree: after a global install of the published tarballs, 28 of 28 Enterprise plugins active, and a three-cloud scan produced a 76-file evidence pack per cloud. That release was matrix-neutral — 28 Enterprise plugins, 27 of them cloud auditors (55 overall), and seven frameworks, both unchanged. Paired CE 0.2.35 + agent-skill 0.2.33.
Prior: EE 0.32.9 (2026-07-29) — an internal-provenance strip plus a false-clean closure. A compliance report is a document you hand your auditor, and ours carried internal engineering identifiers — roadmap ids, internal release stamps, the name of an internal audit review — in finding titles, on the attestation cover page and in the chain-of-custody record. Measured on a rebuilt three-cloud evidence pack: 686 unexplained internal-marker occurrences → 0 across 105 files, with a positive control in the same run (3,572 benign matches still detected) so the zero is a measurement rather than an absence of looking. And when a cloud plugin could not start — optional SDK absent, 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. Every in-scope control of a cloud that could not be scanned now carries a fail-closed evidence gap. Also in that release: an archived scan re-processed by the new build WARNS instead of failing clean; four report surfaces that contradicted each other on trusted timestamping — which was still on the roadmap at that release, and became opt-in via NSAUDITOR_TSA_URL as of EE 0.33.0 — now say the same verifiable thing; and a new pack scanner that fails closed when its own positive control comes back empty. The paired Community Edition 0.2.34 fixed --out <dir> writing to the parent directory when the directory name contains a dot, made the MCP scan_cloud summary handle both spellings of the evidence-gap prefix, and stopped validate misreporting where plugins came from. Two upgrade notes still apply: (1) the evidence-gap finding title changed at 0.32.9, so suppression rules written against the older text stop matching — the direction is safe (findings resurface rather than hide) but it is silent, so re-check your suppression list; (2) re-scan rather than re-processing scans captured before 0.32.9, as the engine now warns when it is handed an older archive.
Before that: EE 0.32.8 (2026-07-28) — capability-claim honesty pass, part 2 — the air-gapped-delivery class. 27 advertised claims across the three published packages were checked against the code and withdrawn: an arm64 image (the build forces linux/amd64), offline-installable tarballs, monthly NVD feed bundles, an air-gapped install script, and a feed import CLI command with no implementation. Five of the 27 were not documentation but rendered runtime strings — the [COVERAGE GAP] rationale that prints verbatim into the assessor-facing evidence pack was telling the reader to import a feed with a command that does not exist. Nothing was withdrawn by deletion: the air-gap story was rewritten to what the code supports — a linux/amd64 delivery image or npm host install, fully offline ES256 license verification with no phone-home, and offline CVE matching under NSAUDITOR_OFFLINE_ONLY=1 — and ends with an explicit “deliberately not claimed” list, held by two mutation-proven guards. Matrix-neutral — no detection, routing or coverage change; still 28 EE plugins and all seven coverage matrices byte-identical to 0.32.7. The SOC 2 matrix is UNCHANGED at 10 covered / 4 partial / 33 OOS. The paired Community Edition also fixes --out, which silently wrote to the parent directory when the output directory was version-named. Regression 9,280 pass / 0 fail. Paired CE 0.2.33 + agent-skill 0.2.31. The Vanta · Drata · Secureframe GRC connectors ship as before (opt-in, outbound, single-workspace, early-access). And before that: EE 0.32.7 (2026-07-21) — cross-framework routing, so network-scan findings reach every framework that maps their control subject; matrix-neutral.
NSAuditor AI EE generates a Type-I-friendly pre-audit gap report with institutional-level evidence controls.
It maps cloud and network scan findings to specific Trust Services Criteria, produces hash-chained evidence artifacts (cover-page Scope Attestation, SHA-256 chain-of-custody sidecars, and a documented suppression workflow), and ships in machine-readable form suitable for GRC platform ingestion (Vanta + Drata + Secureframe push connectors shipped with scan-time activation, opt-in early-access and ZDE-redacted; live tenant validation in progress; Secureframe's API shape is published-assumed).
It is not a SOC 2 Type II evidence pack on its own (Type II turns on operating effectiveness across a 6–12 month window, and the multi-period roll-up that would produce it is not reachable from any shipped entry point — see the Type I vs Type II section for exactly which parts are and are not wired). It is not a replacement for governance, risk-assessment, or business-continuity evidence (those control families are explicitly out of scope). It is not a substitute for a CPA-firm audit — this is the pre-audit report you give your auditor so they don't bill you for finding what you already knew.
The market split: GRC platforms (Vanta, Drata, Secureframe) automate workflow but lack native vulnerability scanning; legacy scanners (Tenable, Qualys, Rapid7) produce voluminous CVE reports but don't map findings to TSC controls. NSAuditor's wedge is the bridge — deep scanning + auditor-mapped output + GRC API push.
Coverage matrix — AICPA TSC 2017
Source of truth is data/compliance/soc2.json; this matrix mirrors it. A test asserts the two stay in sync.
per-framework citation map makes additional frameworks cheaper to author
--compliance <framework>
Read this: "Covered" means the engine produces direct evidence the auditor can attach to the control. "Partial" means we evidence one dimension of the control (e.g., a point-in-time snapshot) but not the cadence / multi-period dimension. "Out of scope" means the control is fundamentally not addressable by network scanning — a different evidence source is required.
How to run a SOC 2 scan
Once the EE package is installed and your license is activated, every scan can emit SOC 2 evidence by passing --compliance soc2. There are four common configurations — pick the one that matches the audit-readiness you need.
Install & activate (3 lines, no shell-rc edits)
The CE platform ships license install <KEY> which verifies the JWT signature before persisting and stores the key in the platform-appropriate location (macOS Keychain, or ~/.nsauditor/.env mode 0600 on Linux/Windows). No env var setup required.
# Install CE platform + EE package (EE needs npm read-token from your purchase email)$ npm install -g nsauditor-ai @nsasoft/nsauditor-ai-ee# Activate — verifies JWT signature, stores in Keychain / ~/.nsauditor/.env$ 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-04# Verify$ nsauditor-ai license --status✓ Enterprise license active
Backward-compatible: existing setups using NSAUDITOR_LICENSE_KEY env var or ~/.nsauditor/.env continue to work — the multi-source license loader resolves keys in this order: env var (CI/CD wins) → macOS Keychain → file.
Run a basic SOC 2 scan
Single-scan, point-in-time. Produces the 10-file evidence bundle (gap report + scope attestation + chain-of-custody + integrity sidecars). Suitable for internal review and Type I gap analysis. Pick the recipe that matches your scope — on-prem network, AWS, Azure, or GCP (multi-cloud all map to the same soc2.json evidence ledger).
Trusted timestamps (opt-in) + SLA tracking — available as of EE 0.33.0
RFC 3161 trusted-timestamp sidecars (opt-in; third-party non-repudiation) and per-severity SLA / MTTR tracking are now reachable: set NSAUDITOR_TSA_URL to a Time-Stamp Authority of your choosing and every artifact gets a .tsr sidecar, and use --sla-policy for per-severity SLA / MTTR tracking that renders into the report an assessor reads. Timestamping is opt-in with no default, ever — unset means the feature is absent, not “use ours” — so an air-gapped environment simply leaves it unset. What every scan writes regardless: the cover-page Scope Attestation and a SHA-256 chain-of-custody sidecar per artifact.
nsauditor-ai scan --host 10.0.0.0/24 --plugins all --compliance soc2
Push results to your GRC platform
Ships the gap report straight into Vanta, Drata, or Secureframe as TestResult / evidence records with TSC outcome mapping — pushed at scan time (opt-in early-access).
For Type II operating-effectiveness, run the same compliance scan on a fixed cadence (typically weekly or monthly). Keep doing this — the advice is correct and the per-scan records are real. Every run writes a scan_attestation_<framework>.json with a SHA-256 sidecar, so the history accumulates from today. What this release cannot yet do is aggregate it: the recurring-attestation module that would discover prior scans, build the chronological matrix and emit a Type II pack is built but has no CLI, MCP or library caller. Treat the roll-up as roadmap, and the cadence as the thing that makes it retroactively useful the day it ships.
# Example: weekly SOC 2 scan via cron, 6-month assessment window$ crontab -e# 0 3 * * 0 cd /opt/nsauditor && nsauditor-ai scan --host 10.0.0.0/24 \# --plugins all --compliance soc2 \# --output-dir ./scans/$(date +\%Y-\%m-\%d) >> scan.log 2>&1# Generate Type II recurring attestation across the last 6 months$ nsauditor-ai compliance recurring-attestation \
--root ./scans \
--framework soc2 \
--window 6m
Environment variables reference
All SOC 2-related environment variables (Enterprise license required):
Variable
Default
Purpose
COMPLIANCE_FRAMEWORKS
—
Set to soc2 to enable SOC 2 mapping (auto-set when --compliance soc2 passed).
COMPLIANCE_WORM_BUCKET
—
Roadmap — not read by the engine today. NSAuditor validates and reports S3 Object-Lock posture; it does not itself write the archive to a WORM store.
COMPLIANCE_WORM_REDACTION
—
Roadmap — not read by the engine today. Resource redaction on GRC egress is configured in the connector config, not by this variable.
COMPLIANCE_GRC_PROVIDER
—
GRC platform: vanta, drata, or secureframe.
COMPLIANCE_GRC_TOKEN
—
API token for GRC platform push.
COMPLIANCE_TABLETOP
—
Roadmap — implemented in the engine but not yet exposed by a flag.
COMPLIANCE_NTP_STRICT
—
Roadmap — NTP clock attestation is implemented but not yet exposed by a flag.
What you get — output artifacts
Each --compliance soc2 run writes the evidence bundle to out/<scan-id>/. The base bundle is 10 files (14+ when recurring-attestation is configured), and every artifact ships with a .sha256 integrity sidecar.
File
Purpose
scan_compliance_soc2.md
Markdown gap report — engineering / GRC consumption.
scan_compliance_soc2.html
Standalone HTML report (inline CSS, dark theme, "Print to PDF" button) — give this to the auditor.
scan_compliance_soc2.json
Full report data (machine-readable) — for GRC API push or custom downstream tooling.
MTTR section — Mean Time To Remediate by severity with SLA compliance status
Identity verification section — Approver verification band with per-reason breakdown
How to view & verify the results
1. Open the HTML report (the auditor-friendly view)
The HTML report is fully self-contained — inline CSS, dark theme, no external assets, "Print to PDF" button at the top. Open it in any browser and you have the same view your auditor will see.
# macOS$ open out/<scan-id>/scan_compliance_soc2.html# Linux$ xdg-open out/<scan-id>/scan_compliance_soc2.html# Windows> start out\<scan-id>\scan_compliance_soc2.html
2. Verify the chain-of-custody hashes
Every artifact ships with a .sha256 sidecar. All four MUST return OK. If any FAIL, the artifact has been tampered with since generation — reject the report and rerun the scan.
$ cd out/<scan-id>/$ shasum -a 256 -c scan_compliance_soc2.md.sha256scan_compliance_soc2.md: OK$ shasum -a 256 -c scan_compliance_soc2.html.sha256scan_compliance_soc2.html: OK$ shasum -a 256 -c scan_compliance_soc2.json.sha256scan_compliance_soc2.json: OK$ shasum -a 256 -c scan_attestation_soc2.json.sha256scan_attestation_soc2.json: OK
3. Trusted timestamps — opt-in, and verifiable without us
A third-party time floor that an internal actor cannot backdate is the layer above the SHA-256 sidecar, and as of EE 0.33.0 it ships. Set NSAUDITOR_TSA_URL to a Time-Stamp Authority you choose and each artifact gets a .tsr sidecar your auditor verifies with stock OpenSSL, offline, against the authority’s own certificate chain — no NSAuditor software in the path:
Verified against a real public Time-Stamp Authority on 2026-08-07 through the published npm binaries, in both directions: appending a single byte to the artifact turns the same command into Verification: FAILED. Timestamping is opt-in with no default — leave NSAUDITOR_TSA_URL unset and no outbound call is made.
4. Push to your GRC platform (optional)
If COMPLIANCE_GRC_PROVIDER=vanta was set on the scan, the connector already pushed; you'll find the TestResult objects in your Vanta workspace under the matching control IDs. There is no retroactive push subcommand today — re-run the scan with the connector enabled:
Tip — what to send your auditor. Most CPA firms accept the HTML report + the .sha256 sidecars. Zip the entire out/<scan-id>/ directory and share via your usual evidence-collection workflow. The HTML is self-contained so it can be opened from a USB stick in an air-gapped audit room.
✓ Covered controls — direct evidence
For each control below, the engine produces a finding the auditor can attach to the control with stable rationale text.
CC6.1 — Logical access security software, infrastructure, and architectures
"The entity implements logical access security software, infrastructure, and architectures over protected information assets to protect them from security events to meet the entity's objectives."
Source
Example finding
Why it violates CC6.1
auth_agent
SSH password authentication enabled
Password-only SSH violates least-privilege.
auth_agent
Exposed admin panel detected: phpmyadmin
Exposed admin panels violate boundary control.
auth_agent
Telnet service enabled (cleartext protocol)
Cleartext Telnet exposes credentials in transit.
aws-iam-deep-auditor
Console access enabled WITHOUT MFA
CC6.1 requires MFA on privileged accounts (2017 point of focus).
aws-iam-deep-auditor
SHADOW ADMIN: User has full wildcard (*) permissions
Privesc paths violate access boundaries via self-elevation.
azure-cloud-scanner
RBAC: Owner role assigned at subscription scope to principal …
Azure Owner at subscription scope grants full management + role-assignment privileges (the broadest possible). Auditors expect just-in-time PIM elevation or a small fixed group of break-glass accounts.
azure-cloud-scanner
RBAC: Contributor role assigned at subscription scope to principal …
Contributor at subscription scope grants full management of all resources (read+write+delete on every resource type). Long-lived assignments at sub-scope flagged as least-privilege violations.
azure-cloud-scanner
RBAC: User Access Administrator role assigned at subscription scope to principal …
UAA at subscription scope can grant ANY role to ANY principal — equivalent to a privesc primitive. Auditors expect this assigned only to audited break-glass identities.
aws-apigateway-auditor plugin 1050
API Gateway REST/HTTP API has methods/routes with NONE authorization — endpoint exposed without authentication
For Serverless-Framework deployments fronted by API Gateway, the per-method/route authorization type is the canonical CC6.1 entry-point evidence. NONE = CRITICAL; AWS_IAM / COGNITO_USER_POOLS / JWT = PASS; JWT with wildcard audience = INFO with explicit IdP issuer/audience evidence (precedent: Thread CT.5 OIDC heuristic); Lambda authorizer = INFO with manual-verification prompt for the authorizer Lambda function.
aws-lambda-auditor plugin 1080
Lambda function exposes a public function URL with AuthType: NONE + permissive resource-policy principal
Lambda function URLs that bypass IAM authorization are CC6.1 entry-point exposures. Combined with permissive resource-policy principals (e.g., Principal: "*"), this is the Serverless equivalent of an open-to-the-internet admin panel. Maps to CC6.1 + CC6.6.
aws-secrets-ssm-auditor plugin 1090
SSM Parameter classified String (not SecureString) but has a secret-suggestive name (e.g., db_password, api_token)
Plain String SSM parameters are not KMS-encrypted at rest and are readable by any principal with ssm:GetParameter. Secret-suggestive name detection (NFC-normalized at boundary against Unicode-confusable bypass) flags principals storing secrets in the wrong parameter type. ZDE-critical: scanner NEVER calls GetSecretValue / GetParameter — only metadata APIs; verb-prefix denylist regex enforces this at the SDK boundary.
IAM principal has effective kms:Decrypt path via NotAction grant — implicit decrypt
Cross-plugin reconciler walks IAM policies for explicit and implicit decrypt grants (Allow + NotAction:[…] + Resource:* over-grants decrypt by exclusion), then cross-references against destination KMS key policies (plugin 1070) to compute the effective decrypt path. Closes the institutional NotAction-implicit-decrypt false-PASS class.
aws-codepipeline-codebuild-auditor plugin 1100
CodePipeline IAM role has wildcard Action: "*" on Resource: "*" — overprivileged service role
The CodePipeline service role typically runs end-to-end build/deploy. A wildcard Action turns the build path into an effective admin grant. Maps to CC6.1.
RPC widens attack surface across segmentation lines.
azure-cloud-scanner
NSG rule "…" allows inbound from * on port …
Azure NSG inbound rules permitting * / 0.0.0.0/0 / Internet source on management or service ports break network-boundary protection. One issue per permissive rule with source prefix and port range. Anchored regex ~/^NSG rule .* allows inbound/ excludes future SDK-error strings.
aws-apigateway-auditor plugin 1050
API Gateway REST stage has no WAFv2 WebACL associated
The Stage-level WAF association on a REST API is the canonical CC6.6 network-boundary control at the edge. MEDIUM when missing on REST. HTTP API stages emit a stage-waf-not-applicable INFO with the CloudFront-front architectural caveat (HTTP APIs don't support direct WAF — the boundary lives at the CloudFront distribution).
aws-dynamodb-auditor plugin 1060
DynamoDB table has no resource policy denying DeleteItem / UpdateItem for non-audit-writer principals
For audit-store / payroll / financial-batch tables, the table-level resource policy encodes the access boundary INDEPENDENTLY of IAM-policy drift. Surfaced via the 2024 GetResourcePolicy API with soft-degrade for older SDKs (INFO disclosure when SDK is too old). Fine-grained boundary evidence per CC6.6.
aws-backup-auditor plugin 1130 — headline thread
Air-gapped backup vault: destination KMS key policy grants Decrypt/ReEncrypt*/GenerateDataKey to a source-account principal — air-gap broken
For LogicallyAirGappedBackupVault resources (AWS's cryptographically-isolated WORM vault primitive — the canonical institutional ransomware-defense control), the cryptographic-isolation guarantee depends on the destination KMS key policy denying source-account decrypt. The 12-dimension attestation arc verifies across 6 primary mechanisms (vault TYPE air-gapped + ARN account-segment-separation + KMS key-policy clean + KMS Grants clean + MRK-replica topology clean + source-account VPC-endpoint policy clean) plus 6 substrate dimensions. NotPrincipal/NotAction Allow conservatively treated as universal-allow (false-PASS closure). One finding per broken isolation mechanism; CC6.6 mapping is 18 of the 74 air-gapped-vault soc2.json titlePatterns.
aws-backup-auditor plugin 1130
Source-account VPC endpoint policy for com.amazonaws.<region>.kms grants decrypt-class actions to source-account or wildcard principal — VPC-endpoint bypass of air-gap
The VPC-endpoint verifier — the 6th cryptographic-isolation dimension. VPC endpoint policies can grant decrypt path INDEPENDENTLY of IAM and KMS key policies — the institutional class equivalent to the IAM Effective Decrypt-Path plugin's NotAction-implicit-decrypt class, applied to the VPC-endpoint substrate. Filters DescribeVpcEndpoints to KMS service endpoints, walks policy statements, surfaces any source-account-Principal or wildcard-Principal grant of decrypt-class actions. Per-region enumeration memoized within run(); pagination via NextToken with truncated: true gating PASS verdicts.
aws-ec2-sg-perimeter-auditor plugin 1170 v3
Security Group sg-… is transitively reachable from the internet — shortest chain = 2 hops (public-ALB-SG → sg-…)
SG→SG transitive chain reachability: a BFS graph-walk over UserIdGroupPairs references finds SGs that look "private" in isolation (no direct public-CIDR ingress rule) but are reachable through a chain of SG-references from a publicly-exposed SG. The operator-blindness principle rates this HIGH at 2-hop depth (one indirection from a public root). Pre-v3, plugin 1170 audited each SG in isolation — a common multi-tier topology (public-ALB-SG → app-SG → db-SG) would pass all per-SG checks while silently re-opening the perimeter through the SG-reference chain. walkthroughRequired: true surfaces per-hop port records for manual alignment verification (v4 candidate: intersect per-hop port sets). Cross-VPC edges deferred.
aws-ec2-sg-perimeter-auditor plugin 1170 v3
Security Group sg-… is transitively reachable from the internet — shortest chain = 3+ hops (deep chain)
Same BFS walk as the 2-hop case, rated CRITICAL at depth ≥ 3. The operator-blindness principle applies in reverse: the deeper the chain, the less likely an operator notices the exposure — a finding that wouldn't be caught by any per-SG audit dim surfaces only when the full graph is walked. An attacker who pivots through the ALB into the app tier then has SG-policy clearance to talk to the db tier on its declared port, 3+ hops from any public CIDR. Depth cap (default 5, max 20) operator-tunable via transitiveChainDepthCap. Opt out via skipTransitiveReachability: true.
aws-ec2-sg-perimeter-auditor plugin 1170 v3
[plugin 1170] SG→SG transitive reachability walk truncated — raise transitiveChainsPerTargetCap or transitiveChainDepthCap
INFO evidence-gap trailer: emitted when the BFS walk hits the per-target chain cap (default 10) or the depth cap (default 5). Distinguishes "raise chainsPerTargetCap" from "raise depthCap" with separate reason strings — so auditors know whether the truncation was breadth-bounded or depth-bounded. False-CLEAN class: a deeply-buried CRITICAL exposure beyond the depth cap would not surface without raising the cap. Per-region per-SG truncation count surfaced in details.truncatedTargetCount.
Expired certs invalidate the in-transit trust chain.
crypto_agent
Self-signed TLS certificate
Certificates from trusted CAs required in production.
crypto_agent
Missing HSTS header on HTTPS
HSTS is the baseline defense against TLS-stripping.
aws-apigateway-auditor plugin 1050
API Gateway custom domain configured with TLS_1_0 security policy
For Serverless deployments with custom domains, the API Gateway TLS policy is the canonical CC6.7 in-transit protection control at the edge. TLS_1_0 = HIGH; TLS_1_2 / TLS_1_3 = PASS; unknown/missing = MEDIUM. Includes worst-policy tracking across mixed-config v2 domains (R1-CRITICAL-1 fold) — pre-fold the picker was INVERTED, upgrading TLS_1_0 → TLS_1_2 across mixed configs and masking deprecated listeners as PASS.
CC6.8 — Prevention and detection of unauthorized or malicious software
Source
Example finding
Why it violates CC6.8
service_agent
End-of-life Apache 2.2.x on port 80
EOL software no longer receives security updates.
intelligence_engine
CVE-2023-38408 — OpenSSH 8.2p1
Matched CVEs evidence unpatched components.
config_agent
Server version disclosed: nginx/1.18
Banner disclosure enables reconnaissance of vulnerable versions.
CC7.1 — Detection of changes to system configurations / vulnerabilities
This is the vulnerability-management control. Major audit firms typically interpret CC7.1 as requiring automated scanning, even though SOC 2 itself never uses the phrase "vulnerability scanning."
Source
Example finding
Why it violates CC7.1
intelligence_engine
CVE-2023-38408 (CVSS 9.8) — OpenSSH 8.2p1
CVE matching is the canonical CC7.1 evidence per major audit-firm guidance.
service_agent
End-of-life Apache 2.2.x
EOL detection is a positive CC7.1 signal.
config_agent
Debug endpoint(s) exposed on port 8080
CC7.1 expects detection of misconfigurations introducing vulnerability.
config_agent
HTTP directory listing enabled on port 80
Misconfiguration introducing vulnerability.
aws-s3-auditor
Access logging not enabled — audit trail gap
S3 server-access logs are the canonical AWS evidence stream for object-level access detection. Without them, post-incident forensics has no log to walk.
aws-cloudtrail-auditor
Trail X has log file validation disabled (LogFileValidationEnabled=false)
Without log-file validation, CloudTrail cannot detect post-hoc log tampering — the auditor's primary forensic record can be silently modified. (plugin 1040)
aws-apigateway-auditor plugin 1050
API Gateway stage has no AccessLogSettings.DestinationArn — endpoint-level request log missing
For Serverless-Framework deployments, the API Gateway access log is the canonical CC7.1 detection-of-changes evidence at the entry point. Without it, post-incident forensics has no per-request log to walk. MEDIUM.
aws-dynamodb-auditor plugin 1060
CloudTrail does not log AWS::DynamoDB::Table data events while DynamoDB tables exist — the audit-the-auditor gap
The canonical "audit-the-auditor" failure: a malicious insider with dynamodb:PutItem on an audit-store table can write false records (or delete real ones) and no log records the action. Cross-references caller-supplied opts.trailDataEvents from plugin 1040 — orthogonal plugin composition. HIGH when coverage absent + tables exist.
aws-codepipeline-codebuild-auditor plugin 1100
CodePipeline latest execution is older than the configured cadence — stale build pipeline
Build-pipeline runtime-state audit: if the pipeline's latest execution is older than the configured cadence, it isn't actively defending the build path. CC7.1 detection-of-change evidence on the build-pipeline substrate itself.
aws-backup-auditor plugin 1130
Backup vault has no Restore Testing Plan — recoverability never exercised
The institutional ransomware-defense pattern requires periodic restore-testing to verify recoverability. A vault with no associated Restore Testing Plan has no evidence that the backups CAN be restored — the canonical "backups exist but are dead" failure mode. Maps to CC7.1 detection of recoverability change.
aws-s3-lifecycle-replication-auditor plugin 1120
S3 cross-region replication source has no destination-bucket reachability — silent replication failure
The destination-reachability verifier closes the silent-PASS class where replication source FAILED but emitted clean: cross-region destination-bucket reachability is verified (destination IAM denial or bucket missing surfaces explicitly rather than the source-side "configured" status masking the actual failure).
aws-inspector2-guardduty-auditor plugin 1200
EventBridge rule has a dead target — Lambda function deleted, SNS topic detached, or SQS queue non-existent (companion LOW alongside PASS)
Dead-target companion-LOW: even when an EventBridge rule exists and has targets (events:ListTargetsByRule returns non-empty), per-target liveness probes verify that each target actually exists. A rule whose target ARN points to a deleted Lambda, detached SNS topic, or missing SQS queue silently drops every finding it routes — the detection substrate is present on paper but non-functional. The plugin surfaces this as a companion LOW alongside the PASS verdict with the dead ARNs listed. Routes to CC7.1 (substrate-with-dead-targets). Three target types covered: Lambda (lambda:GetFunction full qualified ARN — alias/version correctness verified server-side), SNS (sns:GetTopicAttributes), SQS (sqs:GetQueueUrl + sqs:GetQueueAttributes partition-aware for GovCloud / aws-cn / ISO). Opt out: skipTargetLivenessProbe: true.
CC7.2 — Monitoring of system components and operation for anomalies Covered
"The entity monitors system components and the operation of those components for anomalies that are indicative of malicious acts, natural disasters, and errors affecting the entity's ability to meet its objectives."
The aws-cloudtrail-auditor (plugin 1040) covers CC7.2 by auditing the AWS-native monitoring substrate end-to-end: CloudTrail trail health, CIS AWS Foundations Benchmark v1.5 §3.1–3.14 alarm coverage, and AWS Config recorder state. The v2 metric-filter audit replaces the v1 alarm-name-substring heuristic with the auditor-canonical logs:DescribeMetricFilters evidence stream, and multi-region trail enumeration is ON by default (36 canonical AWS regions; region-list version stamp 2026-05).
Source
Example finding
Why it violates CC7.2
aws-cloudtrail-auditor
CloudTrail: no trails configured for this account — zero audit log coverage
Zero trails = zero management-plane event capture. Issue text includes an AWS Organizations sub-account OrgTrail caveat (details.possibleOrgTrailMember: true) so reviewers know when to verify centrally aggregated coverage. CRITICAL.
aws-cloudtrail-auditor
Trail X is not multi-region (IsMultiRegionTrail=false)
A single-region trail blinds the auditor to out-of-region API activity — attacker-pivoted regions go unmonitored. CIS AWS Foundations 1.5 §3.0 + SOC 2 institutional guidance both require IsMultiRegionTrail=true. HIGH.
aws-cloudtrail-auditor
Trail X does not log data events (S3 object-level / Lambda invocation)
Without data events, the auditor sees no object-level access evidence — exfiltration via GetObject is invisible. Handles both classic EventSelectors.DataResources and modern AdvancedEventSelectors. MEDIUM.
aws-cloudtrail-auditor
Trail X is configured but logging is stopped (IsLogging=false)
The monitoring substrate must be ACTIVE. A trail configured but with IsLogging=false captures no events. HIGH.
CIS Foundations Benchmark 1.5 §3.1–3.14 enumerates the canonical 14 alarm classes; the plugin emits ONE finding per missing class. Severity per institutional audit-firm practice: cis-3.3 = CRITICAL; cis-3.2 / 3.5 / 3.7 / 3.8 / 3.9 = HIGH; remaining 9 classes = MEDIUM. v2 evidence: filterPresent: true, covered: false distinguishes "filter exists but no alarm correlated" from "no filter at all" (different remediation templates).
aws-cloudtrail-auditor
Cross-account LogGroup AccessDenied during v2 metric-filter audit
Aggregate HIGH evidence-gap finding (details.evidenceGap: true, cisId: "cis-coverage-partial-v2") when a trail in App-Account ships to a Security-Account LogGroup that the scanner cannot read. Closes the institutional false-negative class where pre-fold v2 would have emitted bogus "filterPresentNoAlarm" findings instead.
aws-cloudtrail-auditor
AWS Config has no configuration recorders
AWS Config provides resource-state change history; without it, the auditor has no configuration-drift evidence stream. The plugin routes by AWS Organizations ConfigurationAggregator presence + STS GetCallerIdentity account-coverage cross-reference: org/account-list aggregator with the current account in source list → no finding (deterministic PASS); not in any list → HIGH (real CC7.2 evidence gap); no aggregator visible → HIGH. HIGH.
aws-cloudtrail-auditor
Trail bucket has no Object Lock (SEC 17a-4 / FINRA 4511 WORM evidence)
Per-trail S3 destination audit: Object Lock GOVERNANCE mode emits CRITICAL (bypass-able via s3:BypassGovernanceRetention); no Object Lock emits CRITICAL; retention below applied baseline (default 7y SEC 17a-4) emits MEDIUM. Maps to BOTH CC7.2 (monitoring substrate storage layer) and C1.2 (disposal of confidential info).
CC7.3 — Evaluation of security events to determine response Covered
"The entity evaluates security events to determine whether they could or have resulted in a failure of the entity to meet its objectives (security incidents) and, if so, takes actions to prevent or address such failures."
NSAuditor covers CC7.3 by evidencing the AWS-canonical event-evaluation primitive: CloudWatch alarm coverage tied to the CIS §3.1–3.14 baseline. CloudWatch alarms convert raw CloudTrail events into actionable signals routed to SNS topics, PagerDuty, etc. — an alarm class with no alarm = no automated evaluation path = security events accumulate without triggering response.
CloudWatch alarms are the AWS-canonical evaluation-and-routing primitive. Missing alarms means no automated evaluation path for this event class.
aws-cloudtrail-auditor
Trail X has log file validation disabled
CC7.3 evaluation requires trustworthy evidence. Without LogFileValidationEnabled, the auditor cannot verify post-incident that the events used in the evaluation were unmodified.
aws-cloudtrail-auditor
Filter pattern matches CIS hint but no alarm correlates (cis-alarm-coverage-filter-no-alarm)
v2 metric-filter audit category — distinct from "no filter at all" because the gap is in the routing not the capture. Routes to a different remediation template. Issue text mentions Lambda subscription filters / Kinesis Firehose / non-CloudWatch routing alternatives + auditor cross-check via aws logs describe-subscription-filters (avoids false-positives for shops routing via SIEM bypass).
Auditor evidence pack: the per-scan summary.cisAlarmCoverage shape carries evidenceMethod: "metric-filter-correlation-v2" (default; v2 auditor-canonical evidence stream) or "alarm-name-substring-heuristic-v1" + v2FallbackReason (transparency layer when v2 unavailable). summary.scanScope carries {regionsScanned[], regionsWithAccessDenied[], regionsWithCredentialFailure[], regionListVersion: "2026-05", callerIdentity, configAggregators, s3DestinationAudit, throttleRetriesByApi, throttleBudgetExhaustedByApi} — every multi-region / cross-account / split-IAM evidence gap surfaces honestly.
C1.1 — Identification and disposition of confidential information
(Only assessed if Confidentiality is in your audit scope — this is one of the optional categories.)
Partial public access block — missing one or more settings
Auditors expect all four settings (BlockPublicAcls / IgnorePublicAcls / BlockPublicPolicy / RestrictPublicBuckets). A partial PAB still leaves at least one bypass route.
aws-s3-auditor
Bucket policy grants public access
Permissive bucket policy violates confidentiality boundary at storage layer.
aws-s3-auditor
No default encryption configured
C1.1 requires encryption-at-rest for confidential data.
aws-s3-auditor
Server-side encryption uses AES256 (not KMS-CMK)
KMS customer-managed keys give you rotation, audit, and crypto-shredding control that AES256 (AWS-managed) does not. Severity LOW by default; MEDIUM when bucket name matches AWS_S3_AUDIT_CONFIDENTIAL_BUCKETS.
azure-cloud-scanner
Storage account default network access is set to Allow
Azure Storage accounts with defaultAction: Allow on networkRuleSet accept connections from any IP unless an explicit deny rule fires (equivalent to AWS BlockPublicAcls=false). For confidential workloads, auditors expect defaultAction: Deny + an explicit allow-list of approved networks / private endpoints.
azure-cloud-scanner
Storage account allows public blob access
allowBlobPublicAccess=true permits anonymous read access to any container marked public. Direct confidentiality-boundary violation. Auditors require allowBlobPublicAccess=false + container-level public access (AccessLevel.Blob / AccessLevel.Container) also disabled.
aws-dynamodb-auditor plugin 1060
DynamoDB table encrypted with AWS-managed KMS key (:alias/aws/dynamodb) — not customer-rotatable
Customer-managed KMS aliases (:alias/<customer-alias>) → PASS; AWS-managed alias (:alias/aws/dynamodb) → MEDIUM (not customer-rotatable); :key/UUID ARN form → LOW unverifiable with explicit aws kms describe-key verification prompt. The LOW-unverifiable case becomes a deterministic PASS/MEDIUM when plugin 1070 is in the same scan (the _describeKeyManager() helper exported by 1070 is consumed by 1060 via opts.keyManagerByArn — closes the deferred KMS key-manager cross-reference).
aws-kms-auditor plugin 1070
KMS key policy grants kms:* to wildcard principal — unconditional cryptographic-boundary takeover
Wildcard-principal classifier across 5 severity tiers: CRITICAL unconditional kms:* takeover; HIGH for sensitive actions (kms:Decrypt, kms:ScheduleKeyDeletion); INFO read-only-only; PASS no-wildcard. Coverage spans Principal.AWS / Federated / Service / CanonicalUser shapes + case-insensitive AWS/action matching + NotPrincipal-Allow + NotAction-Allow + glob-action coverage (kms:Encrypt* / kms:Sign*). Maps to CC6.3 + C1.1. 77 new tests.
aws-lambda-auditor plugin 1080
Lambda function uses EOL runtime (e.g., nodejs16.x, python3.7) — institutional-CRITICAL
Runtime EOL detection is case-normalized at the SDK boundary per aws_string_case_normalization (institutional-CRITICAL fold: pre-fold a runtime string returned by Lambda with different casing would silently bypass the EOL set check). Closes the runtime-EOL false-PASS class.
C1.2 — Disposal of confidential information Covered (plugin 1130)
"The entity disposes of confidential information to meet the entity's objectives related to confidentiality."
(Only assessed if Confidentiality is in your audit scope — same as C1.1.)
NSAuditor evidences the disposal control by detecting buckets that lack the institutional WORM and tamper-resistance primitives. SEC Rule 17a-4 and FINRA 4511 require S3 Object Lock in COMPLIANCE mode — auditors specifically reject GOVERNANCE-mode buckets as evidence stores because the override permission (s3:BypassGovernanceRetention) is by design, not an emergency break.
Source
Example finding
Why it violates C1.2
aws-s3-auditor
Object Lock not configured
S3 Object Lock is the institutional WORM control. Without it, retention windows cannot be cryptographically enforced — an insider with bucket-write IAM can delete confidential records before retention expires. Maps to SEC Rule 17a-4 / FINRA 4511.
aws-s3-auditor
Object Lock GOVERNANCE mode (use COMPLIANCE for WORM)
Object Lock has two modes: COMPLIANCE (immutable — not even root can delete before retention expires) and GOVERNANCE (any principal with s3:BypassGovernanceRetention can delete). Auditors reject GOVERNANCE-mode buckets as evidence stores. The Object-Lock-enabled bit alone is not sufficient evidence of WORM.
aws-s3-auditor
MFA Delete not enabled
Versioning alone is not tamper-resistant — a single insider with bucket-write IAM can permanently delete a version. MFA Delete requires a second factor at delete-version time. Only emitted when versioning is enabled (otherwise the finding is meaningless).
aws-backup-auditor plugin 1130 — headline thread
Backup vault is NOT a LogicallyAirGappedBackupVault — no cryptographic-isolation guarantee on the disposal substrate
Per SEC Rule 17a-4 and FINRA 4511, the disposal substrate for confidential records must guarantee tamper-resistance under insider compromise. AWS's LogicallyAirGappedBackupVault is the canonical institutional control. Vault TYPE attestation is the 1st of 6 cryptographic-isolation mechanisms verified by the air-gapped-vault attestation arc. 25 of the 74 air-gapped-vault soc2.json titlePatterns map to C1.2 — making this the most-evidenced control in the air-gapped-vault arc.
aws-backup-auditor plugin 1130
Air-gapped vault has KMS Grants on the destination key with source-account GranteePrincipal + decrypt-class Operations — Grants bypass
The KMS-Grants verifier — the 4th cryptographic-isolation dimension. KMS Grants bypass the key-policy entirely; an insider compromise of the source account can use a previously-issued Grant to decrypt vault contents even when the key policy is clean. Closes the institutional class where the KMS key-policy clean attestation alone produces false-clean evidence.
aws-backup-auditor plugin 1130
Air-gapped vault destination KMS key has an MRK replica in the source account — multi-Region Key topology breaks the air-gap
The multi-Region-Key topology verifier — the 5th cryptographic-isolation dimension. KMS multi-Region Keys (MRKs) share key material across replicas; an MRK replica in the source account decrypts the vault contents independently of the destination key. The verifier checks: no MRK replica in source account, primary not in source account, primary key region matches vault region.
IAM principal has effective decrypt path to a confidential-data KMS key via cross-policy reconciliation
Disposal-substrate integrity depends on the effective set of principals that can decrypt — not just the explicitly-named ones in any single policy. The cross-plugin reconciler walks IAM + KMS key-policies together, surfacing the effective decrypt-capable principals. Maps to C1.2 + C1.1.
Severity classifier:AWS_S3_AUDIT_CONFIDENTIAL_BUCKETS=name1,name2 (comma-separated, case-insensitive substring match) escalates the C1.2 + KMS-CMK findings from LOW to MEDIUM for matched buckets. Tag-based classification is on the roadmap.
⚠ Partial controls — single-dimension evidence
NSAuditor evidences one dimension of these controls (typically the configuration-state-at-this-moment dimension). The CADENCE / multi-period / process dimension requires additional evidence sources. The renderer surfaces a ⚠ Coverage caveat: line on every partial control.
Control
TSC title
What we evidence
What's missing (and from where)
CC6.3
System access removal and modification
Stale IAM access keys, multiple active keys (aws-iam-deep-auditor)
Removal cadence — recurring-scan attestation provides the multi-period evidence dimension.
CC8.1
Change management and authorization
Snapshot of current configuration + scanner version delta detection
Environmental protections, software, data backup processes, recovery infrastructure
Exposed-availability-target inventory + S3 versioning posture + GRC connector duration cap + S3 cross-region replication topology (aws-s3-lifecycle-replication-auditor, plugin 1120) + AWS Backup substrate end-to-end via aws-backup-auditor (plugin 1130 — Plans, Vaults, Recovery Points, Selections, Frameworks, Restore Testing Plans, ReportPlans, Legal Holds, VaultType, Vault Tags, Vault Access Policy). The 12-dimension air-gapped vault attestation arc for LogicallyAirGappedBackupVault resources substantially closes the previously-documented "Backup/recovery posture itself" gap. 14 of the 74 air-gapped-vault soc2.json titlePatterns map to A1.2.
Cadence dimension (recurring-scan attestation of recovery-test outcomes) — this is the roadmap item that would promote A1.2 from partial to covered. Recurring-scan attestation is implemented but not wired into the shipped scan path, so A1.2 remains partial in the current matrix. AWS RTO/RPO infrastructure attestations remain the canonical pair on the cloud-provider side.
Application-tier processing integrity (write-through validation, idempotency, exactly-once semantics) — requires Lambda runtime assurance (on the roadmap). The partialReason in soc2.json is explicit: substrate-only scope; auditor must accept the LOW-PARTIAL confidence.
⚪ Out of scope — what network scanning fundamentally cannot evidence
A SOC 2 audit covers technical, administrative, and physical controls. NSAuditor evidences the technical-network-and-cloud slice. Everything else is genuinely not our job — pretending otherwise would create what auditors call "scope illusion": the false belief that buying a scanner replaces governance work.
The renderer emits all of these as out_of_scope controls in every gap report — auditors immediately see the engine's known boundaries and don't have to guess what wasn't evaluated.
Type I vs Type II support
Audit type
NSAuditor support
Evidence produced
Type I — point-in-time control design
Full
Single scan + cover-page attestation + SHA-256 integrity hashes.
Type II — operating effectiveness over 6–12 months
The recurring-attestation module discovers prior scans, filters by your assessment window, detects cadence gaps and scope drift, and emits a chronological matrix. Compliance status taxonomy:
pass — scans within cadence, no scope drift
pass_with_drift_review — within cadence; scope-drift events surfaced for CC8.1 change-management review
cadence_breach — any inter-scan gap exceeds threshold (CC7.1 finding)
no_evidence — zero scans in the window (distinguishes "scans on disk but outside window" from "truly empty rootDir" via discoveredCount)
SLA & MTTR tracking
Per-severity SLA thresholds from sla.json. Three statuses per finding: compliant, approaching (default 75% of threshold), breached. The renderer separates breachedTotal (raw count of all overdue findings) from breachedEffective (post-compensating-control). Auditors read both — breachedEffective > 0 is a hard CC7.1 finding.
Suppressions with status: accepted_risk + non-empty compensating_control flip a finding's effective SLA status from breached → breached_with_compensating_control. The renderer surfaces an inline disclaimer requiring auditor verification of each compensating-control text.
Suppression workflow — the "what about false positives?" answer
Every real scan produces findings the security team has triaged out — false positives, accepted risks with compensating controls, etc. SOC 2 auditors reject silent deletion of findings (looks like under-reporting) but accept documented exclusions when each one carries a specific match, a non-empty rationale, and an approver.
The compliance engine reads out/<scan-id>/suppressions.json if present and enforces all three fields. Suppressions missing any of them are rejected and the underlying finding stays in fail status — the engine refuses to silently absorb undocumented suppressions.
CLI
# Create a new suppression (auto-generates id, approvedAt, expiresAt)$ nsauditor-ai compliance suppress --finding-id <id> --status accepted_risk# Walk scan history, classify each suppression as active / approaching / expired / no_expiry$ nsauditor-ai compliance review# Refresh expiry; appends renewal entry (audit trail) capturing previous + new expiresAt + approver + rationale$ nsauditor-ai compliance renew --finding-id <id>
Per-status default expiry
accepted_risk — 90 days (compensating controls decay; quarterly review is institutional norm)
false_positive — 365 days (scanner-error classifications don't go stale)
Caller can override via explicit expiresInDays
Cryptographic signing & identity verification
Cryptographic suppression signing (Ed25519, with NFC-normalized payloads per RFC 5198 and identity-registry verification) is written by nsauditor-ai compliance suppress, and as of EE 0.37.0 a compliance report checks the suppression signatures it renders, for approvers whose registry entry carries key material. The verdict names the exact signature bytes it checked and pairs positionally with the record it came from, so it cannot be aliased onto a different record that happens to share an id.
Two axes travel with that verdict. verified answers whether the suppression should stand; cryptoValid answers whether those bytes came from the named key. They diverge on exactly the revoked case — a revoked key's bytes still get checked — which is what makes signing after revocation a cryptographic finding rather than a statement about an operator-editable string. A missing verdict means NOT CHECKED and renders as "signed — not checked by this report"; only a failed check renders "🔴 signature FAILED verification".
The identity-registry layer binds approver names to public keys and authorization scopes (which frameworks an approver may authorize suppressions for); a registry member may carry PEM key material beside its fingerprint, and the fingerprint must equal the one computed from that material or the registry is refused at load rather than silently trusted. Every registry in the field today carries fingerprints only, so the procedural control still carries the weight: every suppression is logged in Appendix B with a rationale, a named approver and an expiry. The suppression-audit module detects governance gaps — late renewals, per-approver patterns, quarterly cadence trends — surfaced as governance bands (HEALTHY / ACCEPTABLE / DEFICIENT / CRITICAL).
Where suppressions show up in the report
Every suppression appears in Appendix B — Accepted Risks & False Positives with control ID, finding text, status (accepted_risk vs false_positive), approver, rationale, and renewal chain. Expired suppressions surface as report.expiredSuppressions[] with a "REVIEW REQUIRED" callout when non-empty.
The Vanta, Drata, and Secureframe push connectors map NSAuditor findings to each platform's TestResult / evidence records and provide the audit-grade push client, wired for scan-time activation (opt-in early-access, ZDE-redacted egress, token never serialized; retry/backoff, deterministic framework-dimensioned idempotency, rate-limit backoff, circuit breaker, per-attempt audit log). Drata and Secureframe use the records model — NSAuditor pushes structured control records to the workspace evidence collection and your platform rules evaluate them; the connector carries the control status verbatim, it does not compute pass/fail, and Secureframe's API shape is published-assumed. Live validation against production tenants is in progress; this is a single-workspace, operator-configured push — not a multi-tenant sync — and the real-Vanta OAuth rebuild is gated on partner intake.
Outcome mapping
NSAuditor status
Vanta outcome
pass
passed
fail (all violations compensated)
passed_with_compensating_control
fail (any uncompensated)
failed
partial
failed (Vanta has no partial; partialReason in description)
accepted_risk
passed_with_compensating_control
false_positive
passed
Reliability features
Pre-flight — single-shot GET to vendor identity endpoint with AbortController timeout
Streaming response cap — MAX_RESPONSE_BYTES=1MiB (CC7.1 input validation at vendor API boundary)
Duration cap — maxTotalDurationMs=180s per push (A1.2 availability bound under Retry-After saturation)
Idempotency — idempotencyKey() with scanId collision disambiguation (~<sha16> suffix)
Description truncation — control descriptions truncate at 8KB with explicit count + scan reference
WORM evidence storage — S3 Object Lock
Write-Once-Read-Many archival for SEC Rule 17a-4 / FINRA 4511 audit compliance. The module ships with strict fail-CLOSED Object Lock validation:
GOVERNANCE mode explicitly rejected — citing s3:BypassGovernanceRetention as the override permission auditors reject. GOVERNANCE-mode allows bucket owners to override retention, making it functionally equivalent to /tmp from the auditor's perspective. This is the #1 institutional rejection cause for "WORM" claims.
O(P×S) safeguard with CORRELATION_SIZE_WARNING_THRESHOLD=1M + onWarn callback
Comparison vs the market
Caveat: competitor capability lists evolve quickly; this table reflects publicly-available 2026-Q1 product documentation. Verify against your actual contract before relying on these comparisons.
Capability
GRC platforms (Vanta / Drata / Secureframe)
Legacy scanners (Tenable / Qualys / Rapid7)
NSAuditor AI EE
Workflow automation + auditor portal
✓
—
integrates with GRC platforms (push)
Native vulnerability scanning
— (relies on 3rd-party)
✓ deep enterprise scanning
✓
TSC control mapping per finding
policy/config only — not vuln findings
partial — policy-pack mapping, not per-finding
✓ direct per-finding mapping with rationale
Cover-page Scope Attestation
varies (workflow-style)
—
✓
SHA-256 chain-of-custody on report bytes
varies
—
✓
RFC 3161 trusted-timestamp signing
—
—
✓ opt-in via NSAUDITOR_TSA_URL — TSA of your choosing
TSA cert chain bundling + validation
—
—
roadmap — implemented, not yet flag-exposed
Documented suppression workflow
workflow only
—
✓ engine enforces rationale + approver
Cryptographic suppression signing (Ed25519), checked for approvers whose registry entry carries key material
—
—
✓ written by compliance suppress, and the report renders a per-record verdict
SLA/MTTR tracking per severity
varies
✓ enterprise tiers
✓ via --sla-policy — failures render into the report
Auditor FAQ — questions your CPA firm asks, answered up front
How do I verify the scope of this report wasn't manipulated post-scan?
Three layered guarantees:
Integrity (against bit-rot, accidental edits, unsophisticated tampering): the cover page is part of the report bytes; .sha256 sidecars verify the report bytes. If the cover-page scope is wrong, the hashes won't match. Always written.
Non-repudiation (against an insider who can regenerate both the report AND the matching sidecar): closeable as of EE 0.33.0, at your option. Set NSAUDITOR_TSA_URL to a Time-Stamp Authority you choose and each artifact then carries an RFC 3161 .tsr sidecar (opt-in, off by default) establishing a third-party time floor no internal actor can backdate. It is opt-in with no default — leave it unset and the SHA-256 chain of custody remains your integrity layer, with this gap named rather than implied covered.
Suppression accountability: every suppression is logged with a rationale, a named approver and an expiry, and renders in Appendix B of the report. Cryptographic signing of those records is implemented but not yet flag-exposed.
What if the security team marked a real finding as "false positive" to make the report look clean?
Multiple controls prevent this:
Suppressions are visible — every one is logged in Appendix B with rationale + approver.
Expiry + renewal discipline — every suppression carries an expiry, and late renewals are flagged. (Cryptographic signing of suppression records is implemented but not yet flag-exposed.)
Identity verification — approvers are cross-referenced against a corporate identity registry with authorization-scope checks.
Late-renewal flagging — suppressions renewed after expiration are flagged LATE or VERY_LATE with governance-band classification.
Quarterly trend analysis — rising late-renewal rates across quarters surface as governance degradation.
How does the scanner handle clock drift?
The NTP probe measures local-clock drift against configurable NTP servers. Drift above threshold triggers a WARN or CRITICAL clock advisory on the cover page. In strict mode (complianceNtpStrict: true), critical drift aborts the compliance run entirely. Probe staleness detection classifies the gap between probedAt and generatedAt to catch backdated or stale reports.
This is a single-point-in-time scan. How does Type-II operating-effectiveness apply?
NSAuditor supports Type II evidence through several mechanisms:
Recurring-scan attestation — multi-scan chronological matrix across 6–12 month windows
SLA / MTTR tracking — mean-time-to-remediate by severity with configurable thresholds
Version delta detection — identifies scanner-version changes to distinguish genuine findings from lifecycle artifacts
Suppression renewal cadence — quarterly trend analysis with governance bands
Why is CC1 (control environment) marked out of scope?
CC1 is about board oversight and organizational ethics — these are inherently human / process artifacts, not network state. We could pretend, but pretending creates more audit risk than admitting the boundary. Pair NSAuditor with a GRC platform (Vanta / Drata / Secureframe) for the governance layer.
What about tabletop exercises for CC4.1 / CC7.3?
The tabletop simulation framework provides probe-event manifests + SIEM detection correlation. You define what you tested, import what was detected, and the correlator produces auditor-grade evidence: detection coverage percentage, per-category breakdown, undetected-probe list, unmatched-SIEM-event list. Configurable coverage bands (50/80 liberal, 75/90 Type II, 85/95 high-assurance) classify the result as critical / acceptable / healthy.
Where can I see the canonical mapping?
The source of truth is data/compliance/soc2.json in the EE package. The full SOC 2 coverage matrix in the EE repo mirrors that file, and a test asserts the two stay in sync.
Ready to ship a SOC 2 audit?
Talk to us about an Enterprise license, or grab the EE package via npm if you've already purchased. Audit-ready evidence in under five minutes from your first scan.