✓ Human-authored analysis; AI used for formatting and proofreading.
"Trusted Advisor says all our S3 buckets are green. Our HIPAA assessment is next month. Are we safe?"
Trusted Advisor is a useful baseline. It checks whether buckets have public access and whether logging is enabled. But it operates on a narrow threat model: "Is this bucket public right now?" Three categories of S3 risk are invisible to it.
Blind spot 1: Incomplete observation data (CTL.S3.INCOMPLETE.001)
Before Trusted Advisor can check a bucket, it needs to read the bucket policy and ACL. What happens if the IAM role running the check lacks s3:GetBucketPolicy permission? Or if the bucket policy explicitly denies the scanner's principal?
Trusted Advisor reports nothing. The bucket doesn't appear in findings because the check couldn't execute. No error or warning. Silence.
Stave treats missing data as a finding, not a pass. The CTL.S3.INCOMPLETE.001 control fires when policy or ACL data is absent from the observation snapshot:
stave evaluate --snapshot observations/snap.json --profile hipaa
── LOW ──
[FAIL] INCOMPLETE.001 — low
Finding: Bucket policy data missing from snapshot — safety cannot be proven
Remediation: Re-run the observation collector with s3:GetBucketPolicy,
s3:GetBucketAcl, and s3:GetBucketPolicyStatus permissions
Absence of evidence is not evidence of absence. If you cannot read the policy, you cannot prove the bucket is safe.
Blind spot 2: Latent public exposure behind PAB (CTL.S3.PUBLIC.005)
A bucket can have a policy that grants s3:GetObject to Principal: "*" and still appear private if Block Public Access (PAB) is enabled. PAB overrides the public policy at the API layer. Trusted Advisor sees "not public" and reports green.
But PAB is a single toggle. One API call s3api put-public-access-block with all flags set to false and the bucket is instantly public. The underlying public policy is latent, waiting to activate.
Stave's CTL.S3.PUBLIC.005 detects this latent exposure:
── MEDIUM ──
[FAIL] PUBLIC.005 — medium
Finding: Public read policy masked only by Public Access Block —
removing PAB would immediately expose the bucket
Remediation: Remove the underlying public-granting policy statement
so the bucket does not depend solely on PAB for protection
AWS Config rule changes, Terraform drift, and well-intentioned "fix the CORS issue" tickets have all disabled PAB on production buckets. If the underlying policy is already public, the exposure is instant.
Blind spot 3: ACL escalation (CTL.S3.ACL.ESCALATION.001)
S3 ACLs have a permission that most engineers have never heard of: WRITE_ACP. This permission lets the grantee modify the ACL itself. If AllUsers has WRITE_ACP, any anonymous user can grant themselves FULL_CONTROL with read, write, delete, and further ACL modification.
Trusted Advisor checks for public READ and WRITE. It does not check for WRITE_ACP or READ_ACP, because these are not direct data access permissions. They are escalation paths.
Stave's CTL.S3.ACL.ESCALATION.001 catches it:
── HIGH ──
[FAIL] ACL.ESCALATION.001 — high
Finding: Bucket ACL grants WRITE_ACP to AllUsers — any anonymous user
can modify the ACL to grant themselves FULL_CONTROL
Remediation: Remove WRITE_ACP grants and enable S3 Public Access Block
with BlockPublicAcls set to true
Trusted Advisor answers: "Is this bucket public right now?" That is a useful but incomplete question. For HIPAA compliance, you also need to answer: "Can I prove this bucket's state?" (incomplete data), "Would this bucket become public with one config change?" (latent exposure), and "Can anyone escalate their own permissions?" (ACL escalation). These three blind spots require a tool that models threat paths, not just current state.
Top comments (0)