# WAF Web ACL Without Associated Resources

> 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.

Source: https://zop.dev/integrations/aws/recommendations/waf-web-acl-without-associated-resources
Updated: 2026-08-19

---

## 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](https://aws.amazon.com/waf/pricing/) (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

```bash
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"
  done
```

Run 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.
