aws-waf-swap-web-acl
Replace a Web ACL with an attacker-controlled permissive one to weaken HTTP-layer filtering (requires owning a substitute Web ACL).
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?webacl) ==
SecurityService
?webacl.provider_type == 'AWS::WAFv2::WebACL'
effective_action_on(?principal, ?webacl) contains 'wafv2:AssociateWebACL'
emit
| source type | Identity |
|---|---|
| target type | SecurityService |
| source | ?principal |
| target | ?webacl |
| permissions | wafv2:AssociateWebACL |
| conditions | iam_permission scp_or_org_policy service_state |
| state logic | CONDITIONAL(service_state) — AssociateWebACL is only an attack primitive if the principal also controls a permissive Web ACL to substitute (either by holding wafv2:CreateWebACL to create a new one, or by already owning another Web ACL in the same scope/region). ACTIVE only if evaluator confirms the principal can provide a substitute Web ACL. BLOCKED if an SCP or permission boundary denies wafv2:AssociateWebACL. |
Narrative
{principal.name} can associate a Web ACL (wafv2:AssociateWebACL). If {principal.name} also controls a permissive Web ACL, this can replace the current protective one, weakening or removing HTTP-layer filtering from protected resources. This reduces detection coverage and may allow previously-blocked traffic - it is a cover-tracks / weaken-defenses action, not an access grant.
Raw rule rules/derived/aws/waf.yaml
id: aws-waf-swap-web-acl
emits: CanModify
description: Replace a Web ACL with an attacker-controlled permissive one to weaken HTTP-layer filtering
(requires owning a substitute Web ACL).
applies_to:
- aws
match:
- - principal: null
- HasPermission
- webacl: null
where:
- node_type(?webacl) == SecurityService
- ?webacl.provider_type == 'AWS::WAFv2::WebACL'
- effective_action_on(?principal, ?webacl) contains 'wafv2:AssociateWebACL'
emit:
source_type: Identity
target_type: SecurityService
source: ?principal
target: ?webacl
permissions:
- wafv2:AssociateWebACL
conditions:
- iam_permission
- scp_or_org_policy
- service_state
state_logic: "CONDITIONAL(service_state) \u2014 AssociateWebACL is only an attack primitive if the principal\
\ also controls a permissive Web ACL to substitute (either by holding wafv2:CreateWebACL to create\
\ a new one, or by already owning another Web ACL in the same scope/region). ACTIVE only if evaluator\
\ confirms the principal can provide a substitute Web ACL. BLOCKED if an SCP or permission boundary\
\ denies wafv2:AssociateWebACL."
confidence: 0.85
derived_from:
- ?principal HasPermission ?webacl (wafv2:AssociateWebACL)
false_positive_note: "AssociateWebACL without a substitute ACL is a no-op. Do NOT emit ACTIVE unless\
\ the principal demonstrably controls another Web ACL in the same scope/region or holds wafv2:CreateWebACL.\
\ This edge is a DEFENSE-EVASION primitive \u2014 it does NOT grant access to the application or data\
\ protected by the Web ACL. Do NOT chain this edge to CanEnterAccount / CanExecuteAs / CanEscalateTo.\
\ Scope to the correct AWS region (CLOUDFRONT scope is us-east-1 only)."
narrative: "{principal.name} can associate a Web ACL (wafv2:AssociateWebACL). If {principal.name} also\
\ controls a permissive Web ACL, this can replace the current protective one, weakening or removing\
\ HTTP-layer filtering from protected resources. This reduces detection coverage and may allow previously-blocked\
\ traffic \u2014 it is a cover-tracks / weaken-defenses action, not an access grant."