aws-s3-disable-bpa-then-expose

s3:PutBucketPublicAccessBlock + s3:PutBucketPolicy enables a two-step escalation to expose the bucket - attacker CAN expose the bucket but it is NOT currently exposed.

derived aws emits ExposedToInternet

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} HasPermission {'bucket': None}

where

node_type(?bucket) == ObjectStorage ?bucket.provider_type == 'AWS::S3::Bucket' ?principal has EFFECTIVE s3:PutBucketPublicAccessBlock on ?bucket ARN ?principal has EFFECTIVE s3:PutBucketPolicy on ?bucket ARN

emit

source typeObjectStorage
target typeAnonymousIdentity
source?bucket
target<AnonymousIdentity>
permissionss3:PutBucketPublicAccessBlock s3:PutBucketPolicy
conditionsiam_permission scp_or_org_policy
state logicPOTENTIAL when both s3:PutBucketPublicAccessBlock AND s3:PutBucketPolicy are confirmed EFFECTIVE on the bucket (identity policy + any bucket policy allow; no SCP deny). The bucket is NOT currently exposed, but the attacker can unconditionally make it public via a two-step escalation (clear BPA flags, then write public policy), regardless of the current BPA state. Upgrade to ACTIVE via rule aws-s3-public-bucket when both steps are executed and the policy is actually written. BLOCKED when an SCP denies either action.

Narrative

{principal.name} has both s3:PutBucketPublicAccessBlock and s3:PutBucketPolicy on {bucket.name}; the principal CAN clear Block Public Access flags and then write a public bucket policy, but the bucket is not currently exposed.

Raw rule rules/derived/aws/s3.yaml

id: aws-s3-disable-bpa-then-expose
emits: ExposedToInternet
description: "s3:PutBucketPublicAccessBlock + s3:PutBucketPolicy enables a two-step escalation to expose\
  \ the bucket \u2014 attacker CAN expose the bucket but it is NOT currently exposed."
match:
- - principal: null
  - HasPermission
  - bucket: null
where:
- node_type(?bucket) == ObjectStorage
- ?bucket.provider_type == 'AWS::S3::Bucket'
- ?principal has EFFECTIVE s3:PutBucketPublicAccessBlock on ?bucket ARN
- ?principal has EFFECTIVE s3:PutBucketPolicy on ?bucket ARN
emit:
  source_type: ObjectStorage
  target_type: AnonymousIdentity
  source: ?bucket
  target: <AnonymousIdentity>
  permissions:
  - s3:PutBucketPublicAccessBlock
  - s3:PutBucketPolicy
  conditions:
  - iam_permission
  - scp_or_org_policy
  state_logic: POTENTIAL when both s3:PutBucketPublicAccessBlock AND s3:PutBucketPolicy are confirmed
    EFFECTIVE on the bucket (identity policy + any bucket policy allow; no SCP deny). The bucket is NOT
    currently exposed, but the attacker can unconditionally make it public via a two-step escalation (clear
    BPA flags, then write public policy), regardless of the current BPA state. Upgrade to ACTIVE via rule
    aws-s3-public-bucket when both steps are executed and the policy is actually written. BLOCKED when
    an SCP denies either action.
  confidence: min(contributing_confidences) * 0.85
  derived_from:
  - ?principal HasPermission ?bucket (s3:PutBucketPublicAccessBlock effective permission)
  - ?principal HasPermission ?bucket (s3:PutBucketPolicy effective permission)
  false_positive_note: "This edge models the CAPABILITY to perform both actions, emitted as POTENTIAL\
    \ (not ACTIVE) because the bucket is not yet exposed. The state represents an attack precondition:\
    \ the attacker can clear BPA, then write a public policy, but these steps must be taken sequentially\
    \ and the policy write must succeed. If an SCP or permission boundary blocks EITHER action, the path\
    \ is BLOCKED. Account-level Block Public Access (s3control:PutPublicAccessBlock / account PublicAccessBlockConfiguration)\
    \ may also apply; this rule covers bucket-level BPA only. When account-level BPA is enabled at RestrictPublicBuckets=true,\
    \ even clearing the bucket-level BPA and writing a public policy will be overridden \u2014 emit BLOCKED\
    \ in that case. This complements rule aws-s3-modify-policy (which emits CanModifyPolicy ACTIVE even\
    \ when BlockPublicPolicy=true, acknowledging that BPA is a separate gate the attacker can clear)."
  narrative: '{principal.name} has both s3:PutBucketPublicAccessBlock and s3:PutBucketPolicy on {bucket.name};
    the principal CAN clear Block Public Access flags and then write a public bucket policy, but the bucket
    is not currently exposed.'
move · open · esc close