Skip to main content

Ensure WAFv2 Web ACL Has At Least One Rule

Overview

This check verifies that your AWS WAFv2 Web ACLs contain at least one rule or rule group. A Web ACL (Web Access Control List) acts as a firewall for your web applications, inspecting incoming HTTP/HTTPS requests and deciding whether to allow or block them based on defined rules.

Risk

An empty Web ACL provides no protection. Without rules, all traffic passes through based solely on the default action, leaving your applications vulnerable to:

  • SQL injection and cross-site scripting (XSS) attacks
  • Bot abuse and credential stuffing
  • Layer-7 DDoS attacks
  • Data exfiltration attempts

Even if your default action is set to "Block," an empty Web ACL offers no intelligent filtering and may block legitimate traffic.

Remediation Steps

Prerequisites

You need:

  • AWS Console access with permissions to modify WAF resources
  • Knowledge of which Web ACL needs rules added
Required IAM permissions

Your IAM user or role needs these permissions:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"wafv2:GetWebACL",
"wafv2:UpdateWebACL",
"wafv2:ListWebACLs",
"wafv2:ListAvailableManagedRuleGroups"
],
"Resource": "*"
}
]
}

AWS Console Method

  1. Open the AWS WAF Console

  2. Select the appropriate scope:

    • Regional for Application Load Balancers, API Gateway, or AppSync
    • CloudFront for CloudFront distributions
  3. Click on the Web ACL that needs rules

  4. Go to the Rules tab and click Add rules > Add managed rule groups

  5. Expand AWS managed rule groups and enable:

    • Core rule set (AWSManagedRulesCommonRuleSet) - protects against common web exploits
    • Known bad inputs (AWSManagedRulesKnownBadInputsRuleSet) - blocks known malicious patterns
  6. For each rule group, set the action to Count initially (this logs matches without blocking)

  7. Click Add rules, then Save

  8. Monitor the results in CloudWatch for a few days, then switch rules from Count to Block once you confirm no legitimate traffic is affected

AWS CLI (optional)

List your Web ACLs:

# For regional resources (ALB, API Gateway, AppSync)
aws wafv2 list-web-acls \
--scope REGIONAL \
--region us-east-1

# For CloudFront distributions
aws wafv2 list-web-acls \
--scope CLOUDFRONT \
--region us-east-1

Get current Web ACL configuration:

aws wafv2 get-web-acl \
--name <your-web-acl-name> \
--scope REGIONAL \
--id <your-web-acl-id> \
--region us-east-1

Update Web ACL with managed rules:

Save this JSON to a file named rules.json:

[
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 0,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet"
}
},
"OverrideAction": {
"Count": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWSManagedRulesCommonRuleSetMetric"
}
},
{
"Name": "AWSManagedRulesKnownBadInputsRuleSet",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesKnownBadInputsRuleSet"
}
},
"OverrideAction": {
"Count": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWSManagedRulesKnownBadInputsRuleSetMetric"
}
}
]

Then update the Web ACL:

aws wafv2 update-web-acl \
--name <your-web-acl-name> \
--scope REGIONAL \
--id <your-web-acl-id> \
--lock-token <lock-token-from-get-web-acl> \
--default-action Allow={} \
--rules file://rules.json \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=<your-web-acl-name>-metric \
--region us-east-1

Replace placeholders:

  • <your-web-acl-name> - Name of your Web ACL
  • <your-web-acl-id> - ID from the list-web-acls output
  • <lock-token-from-get-web-acl> - LockToken from get-web-acl output
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: WAFv2 Web ACL with managed rule group

Parameters:
WebACLName:
Type: String
Description: Name for the Web ACL
Default: my-web-acl
WebACLScope:
Type: String
Description: Scope of the Web ACL (REGIONAL or CLOUDFRONT)
Default: REGIONAL
AllowedValues:
- REGIONAL
- CLOUDFRONT

Resources:
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Ref WebACLName
Scope: !Ref WebACLScope
DefaultAction:
Allow: {}
Description: Web ACL with AWS managed rules
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: !Sub "${WebACLName}-metric"
Rules:
- Name: AWSManagedRulesCommonRuleSet
Priority: 0
OverrideAction:
Count: {}
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesCommonRuleSetMetric
- Name: AWSManagedRulesKnownBadInputsRuleSet
Priority: 1
OverrideAction:
Count: {}
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesKnownBadInputsRuleSet
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesKnownBadInputsRuleSetMetric

Outputs:
WebACLArn:
Description: ARN of the Web ACL
Value: !GetAtt WebACL.Arn
WebACLId:
Description: ID of the Web ACL
Value: !GetAtt WebACL.Id

Deploy the stack:

aws cloudformation deploy \
--template-file template.yaml \
--stack-name wafv2-web-acl-with-rules \
--parameter-overrides WebACLName=my-web-acl WebACLScope=REGIONAL \
--region us-east-1
Terraform (optional)
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}
}
}

variable "web_acl_name" {
description = "Name for the Web ACL"
type = string
default = "my-web-acl"
}

variable "scope" {
description = "Scope of the Web ACL (REGIONAL or CLOUDFRONT)"
type = string
default = "REGIONAL"
validation {
condition = contains(["REGIONAL", "CLOUDFRONT"], var.scope)
error_message = "Scope must be either REGIONAL or CLOUDFRONT."
}
}

resource "aws_wafv2_web_acl" "main" {
name = var.web_acl_name
description = "Web ACL with AWS managed rules"
scope = var.scope

default_action {
allow {}
}

rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 0

override_action {
count {}
}

statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesCommonRuleSetMetric"
sampled_requests_enabled = true
}
}

rule {
name = "AWSManagedRulesKnownBadInputsRuleSet"
priority = 1

override_action {
count {}
}

statement {
managed_rule_group_statement {
name = "AWSManagedRulesKnownBadInputsRuleSet"
vendor_name = "AWS"
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesKnownBadInputsRuleSetMetric"
sampled_requests_enabled = true
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.web_acl_name}-metric"
sampled_requests_enabled = true
}

tags = {
Environment = "production"
ManagedBy = "terraform"
}
}

output "web_acl_arn" {
description = "ARN of the Web ACL"
value = aws_wafv2_web_acl.main.arn
}

output "web_acl_id" {
description = "ID of the Web ACL"
value = aws_wafv2_web_acl.main.id
}

Deploy:

terraform init
terraform plan
terraform apply

Verification

After adding rules, verify the Web ACL is configured correctly:

  1. In the AWS WAF Console, open your Web ACL
  2. Check the Rules tab shows at least one rule or rule group
  3. Confirm the Sampled requests tab shows traffic being evaluated
CLI verification commands
# Check that the Web ACL has rules
aws wafv2 get-web-acl \
--name <your-web-acl-name> \
--scope REGIONAL \
--id <your-web-acl-id> \
--region us-east-1 \
--query 'WebACL.Rules[].Name'

# Re-run the Prowler check
prowler aws --checks wafv2_webacl_with_rules

Additional Resources

Notes

  • Start with Count mode: Always deploy new rules in Count mode first. This logs what would be blocked without affecting traffic. Monitor for false positives before switching to Block mode.

  • CloudFront scope requires us-east-1: When working with CloudFront distributions, you must use the us-east-1 region for all WAF API calls.

  • Rule priority matters: Lower numbers are evaluated first. Place your most important rules (like rate limiting) at lower priority numbers.

  • Cost considerations: AWS WAF charges per Web ACL, per rule, and per million requests inspected. AWS managed rule groups have additional charges. Review pricing before adding multiple rule groups.

  • Consider additional rule groups: Based on your application, you may want to add:

    • AWSManagedRulesSQLiRuleSet - SQL injection protection
    • AWSManagedRulesLinuxRuleSet - Linux-specific exploits
    • AWSManagedRulesAmazonIpReputationList - Known malicious IPs
    • AWSManagedRulesBotControlRuleSet - Bot management (additional cost)