NSAuditor AI EE 0.15.4 Closes the Silent-Overwrite ?versionId= Attack and Differentiates Public WRITE-Class S3 Access
EE 0.15.4 closes two EE 0.15.3 residuals: public ACLs on non-current S3 object versions, and WRITE-vs-READ class differentiation — with zero framework JSON edits.
Nsasoft US LLC has shipped NSAuditor AI EE 0.15.4, the forty-second consecutive trio-publish of its local-first, zero-data-exfiltration enterprise security scanner. The release closes the two residuals carried as deferred in the EE 0.15.3 spec: public ACLs on non-current (overwritten) S3 object versions, and public WRITE-vs-READ class differentiation. Plugin count is UNCHANGED at 28, all six framework coverage matrices are UNCHANGED, and ZERO framework JSON files were edited.
The silent-overwrite attack the scanner missed
EE 0.15.3 closed the fourth and final S3 public-exposure vector at the current-object level — policy × bucket-ACL × PAB × object-ACL. But in a versioned bucket, a private current object can sit on top of a non-current (overwritten) version that retains a public ACL and is still downloadable via ?versionId=<old>. The motivating attack: an adversary PUTs an object with x-amz-acl: public-read, the owner notices the exposure and overwrites it with a private version — the new current version is clean, the scanner passes, and the public payload keeps serving from the old version. Forever.
Plugin 1020 (AWS S3 auditor) now closes this Class-B secondary-path miss with a new step 2c-v: sampled non-current-version ACL enumeration. When GetBucketVersioning Status is Enabled or Suspended (Suspended buckets retain their old versions — the exact silent-overwrite case), the plugin runs ListObjectVersions bounded by the existing AWS_S3_AUDIT_OBJECT_SAMPLE_CAP, filters to non-current versions (IsLatest !== true), skips DeleteMarkers, and inspects each with GetObjectAcl carrying both Key and VersionId. A public AllUsers or AuthenticatedUsers grant emits CRITICAL via the existing "publicly accessible" framework anchor — routing automatically across SOC 2 C1.1, HIPAA §164.312(a)(2)(iv), ISO/IEC 27001:2022 A.5.23 / A.8.3 / A.8.12, and CIS Controls v8 3.3, with no framework JSON change. PAB IgnorePublicAcls neutralizes to LOW informational. The pass is skipped entirely on BucketOwnerEnforced buckets (ACLs are structurally off).
WRITE-vs-READ class differentiation
A public WRITE / WRITE_ACP / FULL_CONTROL grant means anyone can overwrite object contents — a defacement, supply-chain, or malware-staging vector — and is materially worse than a READ-only public grant (anyone can download). Before EE 0.15.4 both surfaced identically, because the public-group classifier ignores the permission verb.
A new module-scoped sibling helper extractPublicWriteGroups (filtering Permission ∈ {WRITE, WRITE_ACP, FULL_CONTROL}) now appends a distinct enrichment line — “Object ACL grants public WRITE-class access (groups) … – anyone can overwrite contents” — plus a state counter, on the already-CRITICAL finding at all three ACL sites (bucket-ACL, current-object, and the new non-current-version dimension). The severity does not change, and no new routable anchor is introduced. The matrix remains unchanged; the byte-locked extractPublicGroups contract and every existing CRITICAL emission are untouched.
Same-session review fold: a Class-F false negative on versioning permissions
An independent false-negative review of the diff surfaced a Class-F gap that was folded in the same session: a role lacking s3:GetBucketVersioning previously left versioning indeterminate and silently skipped the entire version surface. EE 0.15.4 degrades that path to a routed LOW evidence-gap (suppressed on BOE, where ACLs are structurally off). The GetBucketVersioning read is hoisted above step 2c-v to gate the pass; the existing step-4 versioning emission consumes the stored value, so no second API call is made and the emission is byte-identical.
Evidence-gaps reuse the existing anchor — zero framework JSON edits
Every new failure path degrades to a routed LOW evidence-gap via the existing "S3 object-ACL evidence-gap" substring anchor on SOC 2 CC7.1 and HIPAA §164.312(b) Audit Controls. ListObjectVersions AccessDenied names the distinct s3:ListBucketVersions IAM action (a least-privilege role can hold s3:ListBucket but not s3:ListBucketVersions). Per-version GetObjectAcl AccessDenied and other-failure aggregates over the AWS_S3_AUDIT_OBJECT_ACL_PARTIAL_THRESHOLD (default 0.5). Non-current-version list truncation surfaces. Per the conservative-classifier principle: unverifiable ≠ clean; remediation is evidence-collection (grant scopes or raise the sample cap), not boundary-control change.
Six-framework routing, all matrices UNCHANGED
Every new emission reuses an anchor shipped in EE 0.15.3. The CRITICAL inherits "publicly accessible"; all evidence-gaps inherit "S3 object-ACL evidence-gap". No control gained or lost a first-mapping. All six matrices verified unchanged: SOC 2 10/4/33 · HIPAA 7/3/45 · NIST CSF 2.0 13/10/83 · PCI DSS 20/8/39 · ISO/IEC 27001:2022 17/14/62 · CIS Controls v8 17/22/114. The WRITE-class enrichment is descriptive context on an already-routed finding — intentionally NOT a routable emission.
Live AWS smoke — all 4 spot-checks PASS
Against an internal test account in us-east-1, the local 0.15.4 build was verified with four spot-checks all passing: (v1) a public-read V1 object overwritten by a private V2 emitted CRITICAL on the non-current version, with the U+2013 en-dash bytes preserved end-to-end through the real AWS API and GetObjectAcl carrying the non-current VersionId; (v2) a public-read-write object produced the WRITE-class enrichment plus counter; (v3) the EE 0.15.3 current-object regression remained intact; (v4) the versioning gate invoked ListObjectVersions on Enabled buckets. The Class-B miss is proven closed on production. A subsequent published-build re-smoke off the live npm tarball reproduced all four results — no mock-vs-real-SDK regressions through the round-trip.
TDD discipline and regression
Twenty-seven new tests were added (87/87 in tests/aws_s3_auditor.test.mjs): 8 helper micro-cases for extractPublicWriteGroups, 3 WRITE-class enrichment integration tests, 14 non-current-version tests (including IsLatest filtering, DeleteMarker skip, Suspended-bucket enumeration, VersionId in the call, truncation, and PAB neutralization), and 2 review-fold tests covering the GetBucketVersioning AccessDenied evidence-gap and BOE suppression. Full regression is 6628/6628 GREEN (+27 vs the 6601 baseline).
Trio publish and install
EE 0.15.4 ships as the forty-second consecutive trio-publish alongside CE 0.1.85 and agent-skill 0.1.52. All three are live on npm:
npm install -g nsauditor-ai@latest @nsasoft/nsauditor-ai-ee@latest nsauditor-ai-agent-skill@latest
The hexa-framework one-scan workflow remains: --compliance soc2,hipaa,nist-csf,pci-dss,iso-27001,cis-v8 produces six separate auditor-ready evidence packs from a single scan. Zero data exfiltration — all evidence stays inside your infrastructure.
Full release notes at the NSAuditor AI Enterprise Edition page.



