I tried Dynamic Label Interpolation with AWS WAF to test dynamic forwarding of bot information and custom block pages

I tried Dynamic Label Interpolation with AWS WAF to test dynamic forwarding of bot information and custom block pages

We verified two scenarios: one using AWS WAF Dynamic Label Interpolation to dynamically forward Bot Control labels to request headers in a single rule, and another using Synthetic Labels to embed IP addresses and request IDs into block pages.
2026.07.22

This page has been translated by machine translation. View original

Introduction

On May 11, 2026, AWS WAF Dynamic Label Interpolation became available in all regions where AWS WAF is supported. Additionally, on July 21, detailed use cases were published on the Security Blog.

https://aws.amazon.com/about-aws/whats-new/2026/05/aws-waf-dynamic-label-interpolation/

https://aws.amazon.com/blogs/security/do-more-with-aws-waf-labels-using-dynamic-label-interpolation/

According to the official blog, AWS WAF Bot Control identifies and assigns labels to more than 650 bots and agents. However, traditionally it was necessary to write individual rules for each label to perform header insertion or response control. With Dynamic Label Interpolation, label values can be embedded within rules using the ${namespace:} syntax, allowing a single rule to cover an entire namespace. In this article, we verified the following two scenarios using a minimal configuration of ALB + Regional WAF.

  • Scenario 1 — Dynamically forward labels assigned by Bot Control to request headers using ${namespace:}, reducing rule management costs
  • Scenario 2 — Embed Synthetic Labels (IP and request ID) into custom block responses to facilitate tracking during support inquiries

Verification Details

Verification Environment

Item Details
Client curl 8.18.0 (with various User-Agents specified)
ALB Fixed response 200 (no target group required)
AWS WAF Regional WebACL, Bot Control Common (InspectionLevel: COMMON)
Bot Control OverrideAction Count
Region ap-northeast-1
Deployment Method CloudFormation

WAF rule evaluation order follows ascending priority. In this verification, rules are evaluated in the following order.

  1. bot-control-common (priority: 0) — Bot Control managed rule group. Assigns labels but does not block (OverrideAction: Count)
  2. forward-bot-signals (priority: 100) — Custom rule. References labels assigned by Bot Control and inserts headers
  3. rate-limit-with-debug-page (priority: 200) — Rate-based rule. Responds with a custom block page when the threshold is exceeded

Bot Control is set to OverrideAction: Count so that subsequent rules can reference its labels. See "Prerequisites Discovered During Initial Verification" for details.

Scenario 1: Dynamic Forwarding of Bot Control Labels

Rule Configuration

In the forward-bot-signals rule, LabelMatchStatement with Scope: NAMESPACE matches the entire namespace, and the ${namespace:} syntax dynamically expands label values into headers.

forward-bot-signals rule definition (JSON)
{
  "Name": "forward-bot-signals",
  "Priority": 100,
  "Statement": {
    "LabelMatchStatement": {
      "Scope": "NAMESPACE",
      "Key": "awswaf:managed:aws:bot-control:bot:category:"
    }
  },
  "Action": {
    "Count": {
      "CustomRequestHandling": {
        "InsertHeaders": [
          {
            "Name": "x-waf-bot-category",
            "Value": "${awswaf:managed:aws:bot-control:bot:category:}"
          },
          {
            "Name": "x-waf-bot-name",
            "Value": "${awswaf:managed:aws:bot-control:bot:name:}"
          },
          {
            "Name": "x-waf-bot-signals",
            "Value": "${awswaf:managed:aws:bot-control:signal:}"
          },
          {
            "Name": "x-waf-client-ip",
            "Value": "${awswaf:ip:}"
          }
        ]
      }
    }
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "forward-bot-signals"
  }
}

Test Results

Requests were sent with three User-Agent patterns to verify Bot Control label assignment and the behavior of forward-bot-signals.

Test User-Agent HTTP Status Bot Control Judgment forward-bot-signals
Test 1: curl default UA curl/8.18.0 200 bot:category:http_library + signal:non_browser_user_agent Triggered (header inserted)
Test 2: Googlebot spoofing Googlebot/2.1 200 signal:non_browser_user_agent Not triggered
Test 3: Chrome UA Chrome/126.0 200 — (token:absent only) Not triggered

In Test 1, Bot Control assigned the bot:category:http_library label, which matched the forward-bot-signals condition and triggered header insertion. The expanded values are recorded in the requestHeadersInserted field of the WAF log.

"requestHeadersInserted": [
  {"name": "x-amzn-waf-x-waf-bot-category", "value": "http_library"},
  {"name": "x-amzn-waf-x-waf-bot-name",     "value": "curl"},
  {"name": "x-amzn-waf-x-waf-bot-signals",  "value": "non_browser_user_agent"},
  {"name": "x-amzn-waf-x-waf-client-ip",    "value": "203.0.113.1"}
]

The correspondence between ${namespace:} syntax and expansion results is as follows.

Variable (namespace interpolation) Expansion Result
${awswaf:managed:aws:bot-control:bot:category:} http_library
${awswaf:managed:aws:bot-control:bot:name:} curl
${awswaf:managed:aws:bot-control:signal:} non_browser_user_agent
${awswaf:ip:} 203.0.113.1

In Test 2 (Googlebot spoofing), Bot Control assigned the signal:non_browser_user_agent label, but did not assign a bot:category: label. Since Bot Control uses not only the User-Agent string but also request characteristics such as the source IP to identify bots, this verification could not confirm classification as bot:category:search_engine through UA change alone. Since forward-bot-signals uses the bot:category: namespace as its condition, the rule did not trigger.

In Test 3 (Chrome UA), Bot Control signals labels were not assigned and only token:absent (indicating the AWS WAF token is absent from the request) was assigned, so similarly there was no match with the bot:category: namespace and the rule did not trigger.

According to the official documentation, if multiple labels match in a namespace, they are concatenated with commas. However, this situation did not occur during this verification and was not confirmed.

Prerequisites Discovered During Initial Verification

In the initial verification, OverrideAction was set to None (applying managed rule actions as-is). As a result, the CategoryHttpLibrary rule within Bot Control BLOCKED the request, and it never reached the subsequent forward-bot-signals. The WAF log recorded only the BLOCK by Bot Control, and the requestHeadersInserted field did not appear. Changing OverrideAction to Count causes Bot Control to only assign labels and pass the request through, allowing subsequent rules to reference the labels.

WAF Log: BLOCK with OverrideAction: None (equivalent to Test 1)
{
  "terminatingRuleId": "bot-control-common",
  "terminatingRuleType": "MANAGED_RULE_GROUP",
  "action": "BLOCK",
  "ruleGroupList": [{
    "ruleGroupId": "AWS#AWSManagedRulesBotControlRuleSet",
    "terminatingRule": {
      "ruleId": "CategoryHttpLibrary",
      "action": "BLOCK"
    }
  }],
  "labels": [
    {"name": "awswaf:managed:aws:bot-control:bot:category:http_library"},
    {"name": "awswaf:managed:aws:bot-control:bot:name:curl"},
    {"name": "awswaf:managed:aws:bot-control:signal:non_browser_user_agent"}
  ]
}

Scenario 2: Embedding Synthetic Labels into Custom Block Pages

The rate-based rule rate-limit-with-debug-page BLOCKs IPs that exceed 100 requests in 5 minutes and responds with a custom response body. Synthetic Labels (${awswaf:ip:} and ${awswaf:request_id:}) are embedded in the response body and headers to dynamically display information needed for support inquiries when blocked.

{
  "CustomResponseBodies": {
    "block-page-with-debug": {
      "Content": "<!DOCTYPE html>\n<html>\n<head><title>Access Denied</title></head>\n<body>\n<h1>Access Denied</h1>\n<p>Your IP: ${awswaf:ip:}</p>\n<p>Request ID: ${awswaf:request_id:}</p>\n<p>If you believe this is an error, contact support with the Request ID above.</p>\n</body>\n</html>",
      "ContentType": "TEXT_HTML"
    }
  }
}

Test Results

110 consecutive requests were sent with a Chrome UA to trigger the rate limit and verify the block response. The rate-based rule continuously evaluates the request rate using a 5-minute window, and BLOCKs requests while the threshold is exceeded. The block is lifted once the rate is determined to have fallen below the threshold.

The HTML response body received by the client when blocked is shown below.

<!DOCTYPE html>
<html>
<head><title>Access Denied</title></head>
<body>
<h1>Access Denied</h1>
<p>Your IP: 203.0.113.1</p>
<p>Request ID: 1467396511:1-6a5fdb1c-7efa072b7f5ecd8c3bb60a6c</p>
<p>If you believe this is an error, contact support with the Request ID above.</p>
</body>
</html>

The same Request ID is also inserted in the response header x-blocked-request-id.

x-blocked-request-id: 1467396511:1-6a5fdb1c-7efa072b7f5ecd8c3bb60a6c

In this verification, the Request ID displayed in the response matched the requestId field in the WAF log. This makes it possible to identify the corresponding WAF log entry using the ID reported by the user.

WAF Log: Rate Limit BLOCK (Test 4)
{
  "terminatingRuleId": "rate-limit-with-debug-page",
  "terminatingRuleType": "RATE_BASED",
  "action": "BLOCK",
  "responseCodeSent": 403,
  "rateBasedRuleList": [{
    "rateBasedRuleName": "rate-limit-with-debug-page",
    "limitKey": "IP",
    "maxRateAllowed": 100,
    "evaluationWindowSec": 300,
    "limitValue": "203.0.113.1"
  }]
}

Summary

As you add control for each bot type using AWS WAF Bot Control, judgment rules and exception settings per category tend to increase, making WebACL management more complex. Dynamic Label Interpolation enables the dynamic forwarding of categories, names, and signals assigned by Bot Control to request headers on a per-namespace basis. This provides a simple means of passing information to the origin without enumerating per-category values in WAF rules.

This allows you to consider a configuration where, instead of writing detailed per-category processing in WAF, the judgment results are passed to the origin and the application side selects the necessary processing or response. In this verification, we confirmed that Bot Control label values are dynamically expanded into headers.

Additionally, WAF rules including Bot Control may sometimes result in unintended blocks or support inquiries. By embedding Synthetic Labels into custom block pages and response headers, you can receive a Request ID from blocked users and use it as a clue to trace the corresponding WAF log.

If you are experiencing challenges with the number of Bot Control rules, exception management, or post-block investigation, please try Dynamic Label Interpolation in a verification environment first.

Share this article

AWSのお困り事はクラスメソッドへ