AWS Security Hub · WAF
WAF.10: WAFv2 web ACLs should have a rule or rule group
Written and reviewed by Emnode · Last reviewed
What does AWS Security Hub WAF.10 check?
WAF.10 checks whether a WAFv2 web ACL contains at least one rule or rule group. It reports FAILED when the web ACL is empty. WAFv2 web ACLs are scoped to either `REGIONAL` (ALB, API Gateway, AppSync, Cognito, App Runner) or `CLOUDFRONT` (managed from us-east-1).
Why does WAF.10 matter?
An empty web ACL still has a default action — usually `Allow` — that every request falls through to because nothing is inspecting it first. So it passes 100% of traffic untouched while appearing, in the console and on architecture diagrams, as a deployed firewall. This typically happens when a web ACL is created ahead of its rules, scaffolded from IaC with an empty rules block, or has its last rule removed during troubleshooting.
How do I fix WAF.10?
- Inventory empty web ACLs across both scopes and all regions — `--scope` is required on nearly every `wafv2` call.
- Attach the AWS Managed Rules baseline, in Count mode first on production.
- Promote the rules to enforcing once the metrics are clean.
- Lock the rules baseline into IaC so empties can't be reintroduced.
Remediation script · bash
# Attach the AWS Managed Rules common baseline to an empty web ACL, in Count mode.
# update-web-acl REPLACES the entire Rules array, so supply the full desired set and the current LockToken.
aws wafv2 update-web-acl \
--scope REGIONAL --name public-alb-waf --id a1b2c3d4-0000-1111-2222-3333 \
--lock-token e4f5g6h7 --default-action Allow={} \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=public-alb-waf \
--rules '[{"Name":"AWS-CommonRuleSet","Priority":0,"Statement":{"ManagedRuleGroupStatement":{"VendorName":"AWS","Name":"AWSManagedRulesCommonRuleSet"}},"OverrideAction":{"Count":{}},"VisibilityConfig":{"SampledRequestsEnabled":true,"CloudWatchMetricsEnabled":true,"MetricName":"AWS-CommonRuleSet"}}]'
# Associate a baseline web ACL with an unprotected API Gateway stage (the resource ARN is the stage, not the API).
aws wafv2 associate-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:111122223333:regional/webacl/prod-api-baseline/1a2b3c4d \
--resource-arn arn:aws:apigateway:us-east-1::/restapis/a1b2c3d4e5/stages/prod
# Protect a Network Firewall from accidental deletion.
aws network-firewall update-firewall-delete-protection \
--firewall-name prod-egress-inspection --delete-protection Full walkthrough (console steps, edge cases and verification) in the lesson Protect APIs and edge with WAF.
Is WAF.10 a false positive?
Getting the `--scope` wrong returns an empty list rather than an error, so a web ACL that lives in the other scope can look non-existent when it's simply being queried in the wrong place.
More WAF controls
- WAF.1 WAF Classic global web ACL logging
- WAF.2 WAF Classic regional rules should have a condition
- WAF.3 WAF Classic regional rule groups should have a rule
- WAF.4 WAF Classic regional web ACLs should have a rule
- WAF.6 WAF Classic global rules should have a condition
- WAF.7 WAF Classic global rule groups should have a rule
- WAF.8 WAF Classic global web ACLs should have a rule
- WAF.11 WAFv2 web ACL logging should be enabled