WAF ✓ fields verified against sample logs

AWS WAF Log Format: Field Reference and Example Records

Published

One JSON record per web request that an AWS WAF web ACL evaluated: which rule decided the request, whether it was allowed or blocked, and the client IP, URI, query string and headers WAF saw.

Official documentation: Logging AWS WAF web ACL traffic (AWS WAF Developer Guide) · Log fields (AWS WAF Developer Guide)

Sample record

{"timestamp":1705312800100,"formatVersion":1,"webaclId":"arn:aws:wafv2:us-east-1:123456789012:regional/webacl/MyWebACL/abc123","terminatingRuleId":"Default_Action","terminatingRuleType":"REGULAR","action":"ALLOW","httpSourceName":"ALB","httpSourceId":"123456789012-app/my-alb/50dc6c495c0c9188","ruleGroupList":[],"rateBasedRuleList":[],"nonTerminatingMatchingRules":[],"requestHeadersInserted":null,"responseCodeSent":null,"httpRequest":{"clientIp":"203.0.113.10","country":"US","headers":[{"name":"Host","value":"api.example.com"},{"name":"User-Agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"},{"name":"Accept","value":"application/json"},{"name":"Authorization","value":"Bearer eyJhbGciOiJSUzI1NiJ9..."}],"uri":"/api/v1/products","args":"category=electronics&page=1","httpVersion":"HTTP/1.1","httpMethod":"GET","requestId":"aaa111bbb222"}}

From the LogTriage parser test corpus — synthetic data, no real hosts or users.

Field reference

Field Type Meaning Why it matters for security
timestampe.g. 1705312800100 integer (epoch milliseconds) When AWS WAF evaluated the request. Milliseconds, not seconds — convert before lining records up with ALB, CloudFront or application logs.
webaclIde.g. arn:aws:wafv2:us-east-1:123456789012:regional/webacl/MyWebACL/abc123 string (ARN) ARN of the web ACL that evaluated the request. Identifies the account, Region and scope (regional or CloudFront) when several web ACLs write to one destination.
actione.g. BLOCK string The action AWS WAF took on the request. ALLOW with an attack signature in the URI or headers means nothing stopped it — check the application's own logs for that request.
terminatingRuleIde.g. AWS-AWSManagedRulesSQLiRuleSet string The rule that ended evaluation, or Default_Action when no rule terminated the request. Groups blocks by the kind of attack (SQLi, known bad inputs, common rule set, custom rate limit).
terminatingRuleTypee.g. MANAGED_RULE_GROUP string Type of the terminating rule — REGULAR, MANAGED_RULE_GROUP and RATE_BASED appear in these samples. Separates managed-rule exploit blocks from rate-based throttling, which are different investigations.
ruleGroupList.terminatingRule.ruleIde.g. SQLi_BODY string The individual rule inside the rule group that terminated the request. The most specific label you get — SQLi_BODY, Log4JRCE and CrossSiteScripting_BODY say exactly what was detected.
nonTerminatingMatchingRules array Rules that matched the request but did not end evaluation, such as rules running in Count mode. A request that was allowed can still have matched attack rules here; filtering only on action BLOCK hides it.
rateBasedRuleList.maxRateAllowede.g. 100 integer The configured rate limit of the rate-based rule that applied. Puts a block in context — how much traffic the source had to send before WAF reacted.
responseCodeSente.g. 429 integer or null The response code sent when a custom response is configured; null otherwise. Tells you what the client actually saw, which helps match the event to the attacker's own retry behaviour.
httpSourceNamee.g. ALB string Type of protected resource the request came through. Says which front door was probed when one web ACL protects several resource types.
httpRequest.clientIpe.g. 203.0.113.10 string (IPv4/IPv6) Source address of the request as AWS WAF saw it. The pivot for everything — count blocks, rules and URIs per clientIp to separate one scanner from background noise.
httpRequest.countrye.g. US string (two-letter code) Country derived from the client IP. Useful for grouping, but VPNs, Tor and cloud egress make it weak evidence on its own.
httpRequest.urie.g. /api/v1/products string Path portion of the request. Shows what was targeted; a single source touching many unrelated paths is enumeration.
httpRequest.argse.g. category=electronics&page=1 string Query string of the request, URL-encoded as the client sent it. Carries injection payloads — decode before matching on keywords such as UNION or SELECT.
httpRequest.headers array of name/value objects Request headers AWS WAF captured, each as a separate object with name and value. Where scanner User-Agents and header-based payloads show up; it is a list, so you must search by header name rather than index.
httpRequest.requestIde.g. aaa111bbb222 string Identifier AWS WAF recorded for the request. Anchor for correlating one request across WAF and downstream logs.

What it records

Each line is a JSON object describing one HTTP request that an AWS WAF web ACL evaluated. The record says what WAF decided (action), which rule made that decision (terminatingRuleId, terminatingRuleType and, for managed rule groups, the ruleId inside ruleGroupList), and what the request looked like: httpRequest.clientIp, country, httpMethod, uri, args, httpVersion and the captured headers.

The malicious sample shows the three shapes you most often triage: a managed rule group block (AWS-AWSManagedRulesSQLiRuleSet / SQLi_BODY), a known-bad-inputs block (Log4JRCE) where the payload sits in headers rather than the URI, and a rate-based block that returned responseCodeSent 429. The benign sample shows the baseline — terminatingRuleId Default_Action with action ALLOW.

Where to get it

Enable logging on the web ACL and pick a destination: a CloudWatch Logs log group, an Amazon S3 bucket, or an Amazon Data Firehose delivery stream. The name of the destination must begin with aws-waf-logs-. CloudWatch Logs is convenient for short-term queries; S3 is the cheap option for long retention and for feeding a SIEM in bulk.

Two settings change what you receive, so check them before trusting a quiet log: logging filters, which decide which requests are written at all, and field redaction, which blanks named fields such as an authorization header. httpSourceId identifies the specific protected resource — in these samples the ALB 123456789012-app/my-alb/50dc6c495c0c9188.

Parsing pitfalls

  • Milliseconds. timestamp is epoch milliseconds. Dividing by 1000 is the usual fix when WAF events land fifty years in the future next to your ALB logs.
  • Headers are a list, not a map. httpRequest.headers is an array of {"name": ..., "value": ...} objects in whatever order they arrived. Look up User-Agent by name; never by position.
  • Count mode hides in a different field. Rules that matched without terminating appear in nonTerminatingMatchingRules (and in the per-group nonTerminatingMatchingRules), on records whose action is ALLOW. A query filtered on action == "BLOCK" misses every rule you deployed in Count mode.
  • Percent-encoding. args is stored as sent — id=1%20UNION%20SELECT... in the malicious sample. Decode before keyword matching, or your SQLi searches quietly return nothing.
  • responseCodeSent is usually null. It is populated when a custom response is configured; the rate-based block in the sample shows 429, the managed-rule blocks show null.
  • clientIp is who WAF saw. If another CDN or proxy sits in front of the protected resource, the originating client is in a forwarded header instead, and country is derived from whatever address WAF observed.
  • One JSON object per line. The files are newline-delimited JSON, not a JSON array; parsers that expect a top-level array read zero records.

Detection ideas

  • One source, several rule groups: the same httpRequest.clientIp blocked by SQLi, known-bad-inputs and common-rule-set rules within minutes is an automated scan working through a payload list — the basis of the AWS WAF managed rule exploit block rule.
  • Tooling in the headers: User-Agent values such as sqlmap/1.7.8#stable (https://sqlmap.org) or a bare Mozilla/5.0 (compatible; scanner), even on records with action ALLOW.
  • Payloads outside the URI: ${jndi: appearing in any header value, as the Log4JRCE record shows, where the uri itself is the innocuous /api/v1/health.
  • Rate-based blocks on sensitive paths: terminatingRuleType RATE_BASED against authentication or account endpoints with a scripted agent like python-requests/2.28.0 points at credential stuffing rather than a noisy customer.
  • What got through: for every blocked source, list its ALLOW records in the same window. Those are the requests your application actually handled.

The free browser analyzer runs these checks on an exported WAF log file locally, without uploading it.

Detections and guides for AWS WAF

Frequently Asked Questions

Does a BLOCK record mean the request never reached my application?
A blocked request is stopped at the web ACL and answered by AWS WAF instead of being forwarded to the protected resource, so the application never processes it. The record is still evidence of intent — the same source usually tries other paths and payloads that no rule matches.
What does terminatingRuleId Default_Action mean?
No rule in the web ACL terminated evaluation, so the web ACL's default action decided the request. In the benign sample those records pair Default_Action with action ALLOW, which is what ordinary traffic looks like in these logs.
Why do some attack requests not appear in the log at all?
Logging is configured per web ACL, and logging filters can limit which requests are written. Redaction can also blank individual fields. Treat a gap as a configuration question first, and confirm what the web ACL was set to log during the time window before concluding nothing happened.
Is the request body in the log?
No. The httpRequest object carries the method, URI, query string, HTTP version and headers. Body-inspecting rules such as SQLi_BODY can fire without the body itself being written, so the ruleId is often the only description of what matched.

Analyze AWS WAF logs

LogTriage auto-detects this format, enriches every IP, user agent and hash with threat intelligence, and writes an incident report mapped to MITRE ATT&CK.