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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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. |
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.'