WAF Web ACLs paying the standing fee while attached to nothing
What does ZopNight detect here?
Every WAF Web ACL carries a standing charge of about $5 per month just to exist, before rule and request fees. ZopNight fires only when discovery counts exactly 0 associated resources (an ACL guarding no ALB, API, or distribution) and prices the finding at its full measured monthly cost.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-197 |
| Category | orphan |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | waf_unused.go |
Where it applies
A firewall in front of nothing
A Web ACL does its work by being associated with something: an Application Load Balancer, an API Gateway stage, a CloudFront distribution. Unassociated, it inspects no traffic and blocks no attacks; it is a rule set on a shelf, billing the standing web ACL fee (about $5 monthly, typically measuring ≈$4.93 on the invoice) for shelf space. These usually appear when the protected resource was deleted and the ACL was not, or when someone built the ACL ahead of a launch that changed shape.
Exactly zero, never “unknown”
Discovery counts each ACL’s associations and the rule fires only on an exact zero. The count can also read “unknown”, which is where CloudFront-scoped ACLs and lookups that did not complete land, and unknown never fires. That distinction is the rule’s spine: an ACL that might be protecting a distribution is treated as if it is, and only a positively-confirmed empty association list becomes a finding. An unpriced ACL abstains too; the orphan claim always ships with its real dollar attached.
Delete or attach: both are valid endings
Unlike most orphan findings, this one has a second legitimate resolution. If the ACL embodies real protection policy that some resource should have, associating it is the better outcome than deleting it. The fee was never the problem; the mismatch between policy and attachment was. If the protected resource is gone for good, delete the ACL and sweep any rule groups only it referenced, since unused rule groups can carry their own charges.
Audit associations yourself
aws wafv2 list-web-acls --scope REGIONAL \ --query 'WebACLs[].[Name,ARN]' --output text | while read name arn; do count=$(aws wafv2 list-resources-for-web-acl --web-acl-arn "$arn" \ --query 'length(ResourceArns)') echo "$name: $count associated" doneRun the same with --scope CLOUDFRONT in us-east-1 for distribution-scoped ACLs. That is
the scope this rule’s discovery marks unknown, and therefore exactly the set worth checking by
hand.
The pattern behind repeat findings
Teardowns that delete the load balancer but not its WAF are usually IaC modules with the ACL defined outside the stack being destroyed. Moving the association into the same stack as the protected resource makes the pair live and die together, which retires this finding class rather than one instance of it.