OWASP CRS Rule 920480 Bypass: Mixed-Case CHARSET Evades Charset Allow-List
- Home
- Blog
Advisory: GHSA-89h9-2j8h-9gp2
Tracking ID: EV7-260707
Severity: High
Affected Software: OWASP Core Rule Set (CRS)
Affected Branch: CRS v4.x
Fixed Versions: 4.30.0 and 4.25.2 LTS
A subtle case-sensitivity issue in OWASP Core Rule Set Rule 920480 can allow attackers to bypass the charset allow-list simply by changing the capitalization of the charset parameter inside an HTTP Content-Type header.
The vulnerability demonstrates an important security principle: even when two components process the same HTTP request, differences in normalization can create exploitable gaps.
In this case, HTTP standards treat media-type parameter names as case-insensitive, while the affected CRS rule performed a case-sensitive regular-expression match.
As a result, the WAF and the protected application could interpret the same request differently.
The Vulnerable Rule
CRS Rule 920480, named:
Request content type charset is not allowed by policy
is designed to restrict which character encodings a client can declare through the HTTP Content-Type header.
The rule relies on a pattern similar to:
charset\s*=\s*["']?([^;"'\s]+)
The problem is that the regex expects the literal lowercase string:
charset
without first applying case normalization.
ModSecurity's @rx operator is case-sensitive unless the expression explicitly enables case-insensitive matching.
Therefore:
Content-Type: application/x-www-form-urlencoded; charset=utf-7
can be examined by the rule, while:
Content-Type: application/x-www-form-urlencoded; CHARSET=utf-7
or:
Content-Type: application/x-www-form-urlencoded; cHarSet=utf-7
may bypass the charset extraction stage entirely.
Why This Matters
According to HTTP semantics, media-type parameter names are case-insensitive.
That means applications and HTTP frameworks can interpret all of the following as equivalent:
charset=utf-7
CHARSET=utf-7
Charset=utf-7
cHaRsEt=utf-7
The affected CRS implementation did not.
This creates a parsing discrepancy:
Attacker
│
▼
Content-Type:
CHARSET=utf-7
│
▼
OWASP CRS
Does not recognize "CHARSET"
│
▼
Rule 920480 not triggered
│
▼
Backend Framework
Recognizes CHARSET normally
│
▼
Request body may be decoded
using the attacker-selected charset
This is more than a cosmetic policy mismatch.
Rule 920480 exists in part to reduce encoding-based security-control evasion.
If an application accepts a character encoding that the WAF does not understand or normalize in the same way, malicious content may appear harmless at the WAF layer while being transformed into meaningful attack syntax after backend decoding.
Potential Security Impact
An attacker may declare a non-allow-listed encoding such as:
UTF-7
UTF-16LE
or another encoding supported by the downstream application.
Depending on the target environment, this discrepancy could potentially become an evasion primitive affecting detection of attack classes such as:
- Cross-Site Scripting (XSS)
- SQL Injection
- Remote Code Execution patterns
- Command Injection
- Other signature-based WAF detections
The critical condition is whether the protected application actually honors the attacker-controlled charset during request-body processing.
If the backend always forces UTF-8 independently of the HTTP header, the broader encoding-evasion risk is substantially reduced.
However, even in that situation, the charset policy itself is still bypassed.
Why the Bypass Happens
The affected v4 rule used:
t:none
without applying:
t:lowercase
before attempting to recognize charset.
This is particularly interesting because neighboring CRS rules already demonstrate the intended normalization behavior.
Rule 920530
The related rule for detecting multiple charset declarations applies lowercase normalization before matching the same charset concept.
Rule 920470
The generic illegal Content-Type validation also uses lowercase normalization.
This strongly indicates that Rule 920480's behavior was an inconsistent normalization gap rather than an intentional design choice.
A v4 Regression
The issue affects the CRS v4.x branch.
The older v3.3.x branch is not affected, because its equivalent rule already applies:
t:none,t:lowercase
before performing the comparison.
During the transition from CRS v3 to v4, Rule 920480 was restructured.
The newer implementation introduced an intermediate variable:
tx.content_type_charset
but the previous lowercase transformation was not retained.
That small implementation difference created the bypass.
Affected Versions
The vulnerable version ranges reported in the advisory are:
>= 4.0.0, < 4.25.2
>= 4.26.0, < 4.30.0
Patched versions are:
4.25.2 LTS
4.30.0
CRS v3.3.x is not affected.
Who Should Pay Attention?
Organizations should review their exposure if they:
- operate OWASP CRS v4.x;
- use Rule 920480;
- rely on charset allow-list enforcement;
- run CRS at PL1 or PL2;
- allow applications or frameworks to honor charset information supplied in HTTP requests.
Risk becomes more significant when the backend automatically decodes request bodies according to an attacker-provided charset.
The Fix
The remediation is remarkably small.
The patched rule adds:
t:lowercase
before processing the charset parameter.
Conceptually:
Before:
Content-Type → regex("charset=")
After:
Content-Type
↓
lowercase
↓
regex("charset=")
Now:
charset
CHARSET
Charset
cHaRsEt
are normalized consistently before evaluation.
Regression tests were also added for uppercase and mixed-case parameter names.
Temporary Workaround
Administrators who cannot immediately upgrade can modify the rule action locally after loading CRS:
SecRuleUpdateActionById 920480 "t:lowercase"
This adds the missing lowercase transformation to the affected rule.
Administrators should validate the behavior against their specific ModSecurity or Coraza environment before relying on the workaround in production.
A simple validation request could use:
Content-Type: application/x-www-form-urlencoded; CHARSET=garbage
After applying the mitigation, Rule 920480 should detect the unsupported charset and generate the expected audit event.
Security Engineering Lesson: Normalize Before You Compare
This vulnerability is a useful example of a broader application-security principle:
Security controls and application parsers must agree on normalization.
Case differences, Unicode normalization, URL encoding, path canonicalization, duplicate parameters, conflicting Content-Length and Transfer-Encoding semantics, and charset handling can all produce situations where:
Security control sees A
Backend sees B
That discrepancy is where bypasses emerge.
A strong defensive pattern is therefore:
Normalize
↓
Canonicalize
↓
Validate
↓
Detect
↓
Process
rather than attempting security validation against an ambiguous representation.
Final Assessment
GHSA-89h9-2j8h-9gp2 shows how a very small implementation detail can weaken an otherwise well-designed defensive control.
The vulnerability does not require breaking cryptography or exploiting memory corruption.
Instead, the bypass emerges from a disagreement over a few capital letters:
charset
versus:
CHARSET
For security engineers, WAF developers, and application-security researchers, this is a strong reminder that parser differentials and normalization inconsistencies remain an important attack surface.
Organizations using affected OWASP CRS v4 releases should upgrade to:
4.30.0
or the LTS release:
4.25.2
and verify that charset-policy enforcement operates correctly against lowercase, uppercase, and mixed-case parameter names.
References
GitHub Security Advisory
GHSA-89h9-2j8h-9gp2
HTTP Semantics — RFC 9110 §8.3.1
https://www.rfc-editor.org/rfc/rfc9110#section-8.3.1
OWASP Core Rule Set
https://github.com/coreruleset/coreruleset
In the News
Discovered and reported by JoeCyberTech (GitHub: HackingRepo)
Leave a Comment