I tried the new AWS WAF feature "Parsed Text Transformation" using the CLI
This page has been translated by machine translation. View original
Introduction
With the update on July 29, 2026, pre-parse text transformations became available in AWS WAF.
Pre-parse text transformations are a feature that inserts normalization before parsing query strings into key-value pairs. Traditional text transformations operate on parsed values when inspecting query arguments. Therefore, the handling of delimiters cannot be reflected in the parse results. The official documentation states that pre-parse text transformations can be applied to statements that inspect SingleQueryArgument or AllQueryArguments.
With rules without transformations, neither semicolon-delimited nor URL-encoded semicolon-delimited queries matched. The results after configuring pre-parse text transformations are as follows.
| Query delimiter | Applied pre-parse text transformation (Type) |
|---|---|
| Semicolon-delimited | REPLACE_SEMICOLONS_WITH_AMPERSANDS |
| URL-encoded semicolon-delimited | URL_DECODE → REPLACE_SEMICOLONS_WITH_AMPERSANDS |
Validation Details
Configuring Count Action and Rule Labels
The validation environment is as follows.
| Item | Value |
|---|---|
| AWS CLI | 2.36.11 |
| Region | ap-northeast-1 |
| Web ACL Scope | REGIONAL |
| Backend | Fixed-response ALB |
| Log destination | CloudWatch Logs |
To prevent the block action from interrupting evaluation of subsequent rules, validation rules were set to the Count action, and validation WAF labels were assigned to each rule. WAF log records and HTTP requests were correlated using the query string as a key. Since Count does not block requests, the basis for judgment was labels and nonTerminatingMatchingRules rather than HTTP status. The test Web ACL contained no blocking rules, only these validation Count rules.
# Retrieve LockToken
LOCK_TOKEN=$(aws wafv2 get-web-acl \
--name preparse-test-webacl \
--id 11111111-2222-3333-4444-55555555aaaa \
--scope REGIONAL \
--region ap-northeast-1 \
--query LockToken --output text)
# Configure Count rules and labels
aws wafv2 update-web-acl \
--name preparse-test-webacl \
--id 11111111-2222-3333-4444-55555555aaaa \
--scope REGIONAL \
--default-action '{"Allow":{}}' \
--lock-token "$LOCK_TOKEN" \
--region ap-northeast-1 \
--visibility-config 'SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=preparse-test-webacl' \
--rules file://rules.json
# Verify saved configuration
aws wafv2 get-web-acl \
--name preparse-test-webacl \
--id 11111111-2222-3333-4444-55555555aaaa \
--scope REGIONAL \
--region ap-northeast-1
For comparison, two control rules without pre-parse transformations but with the same matching conditions (ControlNoPreparsePlain, ControlNoPreparseEncoded) were also added. The following is an excerpt from the rule configuration passed to --rules, showing the two rules with pre-parse transformations.
[
{
"Name": "PreparseSemicolon",
"Priority": 2,
"Statement": {
"ByteMatchStatement": {
"SearchString": "cHJlcGFyc2UtcGxhaW4=",
"FieldToMatch": { "SingleQueryArgument": { "Name": "target_plain" } },
"TextTransformations": [ { "Priority": 0, "Type": "NONE" } ],
"PositionalConstraint": "EXACTLY",
"PreParseTextTransformations": [
{ "Priority": 0, "Type": "REPLACE_SEMICOLONS_WITH_AMPERSANDS" }
]
}
},
"Action": { "Count": {} },
"RuleLabels": [ { "Name": "test:preparse-semicolon" } ]
},
{
"Name": "PreparseUrlDecodeSemicolon",
"Priority": 4,
"Statement": {
"ByteMatchStatement": {
"SearchString": "cHJlcGFyc2UtZW5jb2RlZA==",
"FieldToMatch": { "SingleQueryArgument": { "Name": "target_encoded" } },
"TextTransformations": [ { "Priority": 0, "Type": "NONE" } ],
"PositionalConstraint": "EXACTLY",
"PreParseTextTransformations": [
{ "Priority": 0, "Type": "URL_DECODE" },
{ "Priority": 1, "Type": "REPLACE_SEMICOLONS_WITH_AMPERSANDS" }
]
}
},
"Action": { "Count": {} },
"RuleLabels": [ { "Name": "test:preparse-url-decode-semicolon" } ]
}
]
The SearchString values are Base64-encoded strings. cHJlcGFyc2UtcGxhaW4= corresponds to preparse-plain, and cHJlcGFyc2UtZW5jb2RlZA== corresponds to preparse-encoded. The VisibilityConfig for each rule is omitted from the excerpt. After the update, the get-web-acl output confirmed that PreParseTextTransformations and RuleLabels were saved correctly.
Verifying Semicolon-Delimited Queries
Requests with semicolon-delimited and ampersand-delimited queries were sent to the rule configured with REPLACE_SEMICOLONS_WITH_AMPERSANDS.
| Case | Request query | HTTP result | Labels confirmed in WAF log | Non-terminating matching rules |
|---|---|---|---|---|
| Semicolon-delimited | q=safe;target_plain=preparse-plain |
200 / ALLOW | test:preparse-semicolon |
PreparseSemicolon |
| Standard ampersand-delimited (plain) | q=safe&target_plain=preparse-plain |
200 / ALLOW | test:control-no-preparse-plain, test:preparse-semicolon |
ControlNoPreparsePlain, PreparseSemicolon |
For semicolon-delimited queries, only the rule with pre-parse transformation matched, and no control rule label was assigned. For ampersand-delimited queries, both matched, and the labels show that the presence or absence of the transformation made the difference in results.
The following is an excerpt from the WAF log corresponding to the semicolon-delimited request. The labels values include a prefix containing the Web ACL name.
{
"action": "ALLOW",
"terminatingRuleId": "Default_Action",
"nonTerminatingMatchingRules": [
{ "ruleId": "PreparseSemicolon", "action": "COUNT", "ruleMatchDetails": [] }
],
"httpRequest": { "args": "q=safe;target_plain=preparse-plain" },
"labels": [
{ "name": "awswaf:123456789012:webacl:preparse-test-webacl:test:preparse-semicolon" }
]
}
Verifying URL-Encoded Semicolons
Requests for the following two cases were sent to the rule chaining URL_DECODE and REPLACE_SEMICOLONS_WITH_AMPERSANDS.
| Case | Request query | HTTP result | Labels confirmed in WAF log | Non-terminating matching rules |
|---|---|---|---|---|
| URL-encoded semicolon-delimited | q=safe%3Btarget_encoded=preparse-encoded |
200 / ALLOW | test:preparse-url-decode-semicolon |
PreparseUrlDecodeSemicolon |
| Standard ampersand-delimited (encoded) | q=safe&target_encoded=preparse-encoded |
200 / ALLOW | test:control-no-preparse-encoded, test:preparse-url-decode-semicolon |
ControlNoPreparseEncoded, PreparseUrlDecodeSemicolon |
For requests containing URL-encoded semicolons, only the rule chaining decode and replacement matched, and no control rule label was assigned. For ampersand-delimited queries, both rules matched.
Summary
If you are currently combining regular expressions or multiple rules to handle differences in query string delimiters and encoding, using the newly added pre-parse text transformations may allow for simpler management. Each pre-parse text transformation adds 10 WCUs, but as long as the Web ACL total remains at or below the default allocation of 1,500 WCUs, it can be used at no additional charge.


