Friday, 16 October 2026
1 agent hack today▼ 7 vs yesterday (8)

Control characters let crafted cookies slip past Coraza WAF

A parser mismatch in the open-source Go web application firewall meant rules could miss the cookie the backend actually reads, an advisory published 8 October 2026 says.

By The Agentic Times ·

A hidden hand slips a bent key through a grating while guards watch a straight passage—the crooked path reaches the locked door behind them.
A hidden hand slips a bent key through a grating while guards watch a straight passage—the crooked path reaches the locked door behind them. · Illustration: The Agentic Times

A flaw in Coraza, the open-source web application firewall written in Go, allowed attackers to craft a Cookie header that the firewall and the protected application read differently, according to a GitHub security advisory published on 8 October 2026. The issue, tracked as GHSA-g4qm-m288-5cp9, affects releases before 3.8.0 and is fixed in that version.

The advisory describes the problem as cookie parser confusion. Coraza's internal cookie parser trimmed whitespace from the edges of a cookie name and value using Go's net/textproto.TrimString, which strips only the space and tab characters. RFC 6265 excludes the whole C0 control range from both cookie names and values. That gap meant a control character placed directly next to the = separator was absorbed into the adjacent name or value rather than discarded.

The worked example in the advisory is the input a\v=\t', where \v is a vertical tab. Coraza parsed the name as a\v and the value as \t'. Python's http.cookies library parsed the same header as name a and value '. PHP's $_COOKIE produced name a and value \t'. The Node.js cookie package produced name a\v and value '. The advisory notes that RFC 6265 treats this cookie pair as invalid in the first place, so there is no single spec-correct answer, but Coraza's handling diverged from two of the three backends tested.

The practical consequence is a firewall bypass. A rule scoped to a particular cookie name or value, matched through Coraza's REQUEST_COOKIES or REQUEST_COOKIES_NAMES variables, can fail to match the cookie the application goes on to process. The advisory frames this as a bypass for cookie-carried attacks.

The fix trims the full control character range from both ends of the extracted name and value, treating a boundary-adjacent control character as a delimiter rather than part of the token. The maintainers deliberately left one case unresolved: a control character sitting in the middle of an otherwise plausible name, such as ab\vcd. The advisory says the backends themselves disagree there, with Python rejecting the whole pair, PHP stripping the character and Node keeping it, so there is no consensus to align to. That is listed as a separate follow-up.

The advisory also includes an unusual implementation note defending the choice of a hand-rolled byte-wise scan over Go's standard library helpers. The maintainers measured strings.TrimFunc at 167.6 microseconds to parse a 64 KiB Cookie header saturated with control characters on an Apple M2, against 33.9 microseconds for the byte-wise version. They describe that roughly fivefold difference as CPU amplification handed to an attacker, because the input is attacker-controlled and parsed on every request. strings.TrimSpace was rejected as a substitute because it misses most of the control range and additionally trims two multi-byte Unicode characters that a backend would not strip, which the advisory says would reintroduce the same class of disagreement. A benchmark has been added to stop the hot path regressing.

The maintainers say the byte-wise implementation was checked against a TrimFunc-based version across all 16,843,009 byte strings of length zero to three, including invalid UTF-8, with no mismatches.

The advisory credits the original report to a researcher using the handle RelunSec, from InsiteTech.jp, who demonstrated the divergence with a small Flask application and a Go test harness. A correction dated 2 October 2026 notes that current Werkzeug, version 3.1.9, behaves like the Node package, so the name divergence applies to PHP and Python's http.cookies rather than to every Werkzeug release.

Sources

  1. github.comhttps://github.com/advisories/GHSA-g4qm-m288-5cp9