Press enter or click to view image in full size
Around the turn of 2025 and 2026, I researched the ModSecurity WAF for vulnerabilities, specifically its rule component — OWASP CRS. By the end of 2025, after spending three days delving into the process, I discovered a vulnerability in rule 922110, which checks whether the character sets of request parts match an allowed regex.
In this article, I will briefly describe the cause of the vulnerability, focusing more on how to reproduce it and the associated risks. I will save the complete operational chain and workarounds for a separate report.
At first, I looked into a more niche WAF and discovered the flaw. I assumed the vulnerability was specific to that particular product. However, the next morning — already in 2026 — it occurred to me to test this on a pure ModSecurity setup. The result was surprising, as the same behavior was observed there as well…
So my main goal was to blind the WAF and completely bypass its filters, and since I had initially latched onto the idea of request smuggling, I started by trying to break the parser. To do this, I targeted the most challenging aspect for parsers: multipart requests and their character sets. Since the rule engine detects suspicious character sets, I tried to find a way to confuse this check, for example, by overwriting them, which ultimately led to the discovery of the vulnerability.
Join Medium for free to get updates from this writer.
After consulting with the vendor, we concluded that the vulnerability ran even deeper — it affected the ruleset rather than the engine itself. Initially, I approached the investigation with a fresh perspective using a black-box method, so the root cause of the vulnerability wasn’t immediately apparent.
The problem lay in how the rule processes charsets and when it does so.
SecRule MULTIPART_PART_HEADERS "@rx ^content-type\s*:\s*(.*)$" \
"id:922110,phase:2,block,capture,t:none,t:lowercase,chain"
SecRule TX:1 "!@rx ^(?:<-REGEX->)$" \
"setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"With each iteration through the multipart parts, the value of the internal variable TX:1 is overwritten with a new charset value, and ONLY WHEN THE CYCLE IS DONE is it checked for safety. Thus, to exploit this vulnerability, all it takes is a single multipart parameter at the end in a valid encoding.
As I mentioned earlier, to bypass the rule, all you need to do is add a non-functional parameter at the end of the request. Here, I will provide an example of a raw request to illustrate how the attack works.
Here, the request is predictably blocked by ModSecurity because the character set does not match the list of allowed values:
Press enter or click to view image in full size
And here, the request successfully bypasses the security measures because the variable storing the character set has been successfully overwritten with a valid value.
Press enter or click to view image in full size
The main takeaway is that you shouldn’t rely solely on a WAF. Sometimes vulnerabilities exist for years before they’re discovered. And their friends, the bug hunters, will help track them down :)