CVE-2026-114099
Coraza 3.0.0 before 3.8.1 WAF Bypass via JSON Key Collision
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot-separated ARGS_POST names without escaping literal dots, so distinct properties collide. Unauthenticated attackers can add a later dotted property such as account.role that overwrites a malicious nested value, hiding SQL injection payloads from OWASP CRS rules while backends still receive them.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.9
Coraza 3.0.0 before 3.8.1 WAF Bypass via JSON Key Collision
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot-separated ARGS_POST names without escaping literal dots, so distinct properties collide. Unauthenticated attackers can add a later dotted property such as account.role that overwrites a malicious nested value, hiding SQL injection payloads from OWASP CRS rules while backends still receive them.
- Record
CVE-2026-114099- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N - CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
EUVDEUVD-2026-106902
6.9
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot-separated ARGS_POST names without escaping literal dots, so distinct properties collide. Unauthenticated attackers can add a later dotted property such as account.role that overwrites a malicious nested value, hiding SQL injection payloads from OWASP CRS rules while backends still receive them.
- Record
EUVD-2026-106902- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-5gj4-9gm7-2fx2
5.8
Coraza body processor has a JSON key collision that allows unauthenticated attackers to bypass OWASP CRS inspection
Summary
Coraza's JSON body processor converts nested JSON properties into dot-separated ARGS_POST names without escaping dots contained in literal property names. Two distinct JSON properties can therefore collapse into the same Coraza variable
An unauthenticated attacker can place a malicious value in a nested property and then overwrite only Coraza's representation with a harmless dotted property:
{
"account": {
"role": "1' OR '1'='1"
},
"account.role": "safe"
}
Coraza stores both properties as ARGS_POST:json.account.role; the later value safe replaces the SQL-injection value. Standard backend JSON parsers preserve the two distinct properties and expose the malicious nested value as account.role.
This bypasses the complete current OWASP Core Rule Set (CRS) for the hidden value. In the supplied control-pair PoC, CRS v4.25 blocks the nested SQL-injection value with rule 949110. Adding the dotted decoy makes the same attack pass with no interruption, while Go's standard JSON parser still returns the malicious nested value.
Details
The affected component is the JSON body processor in internal/bodyprocessors/json.go.
readJSON creates a single map[string]string and begins every generated path with json:
func readJSON(s string, maxRecursion int) (map[string]string, error) {
res := make(map[string]string)
key := []byte("json")
json := gjson.Parse(s)
err := readItems(json, key, maxRecursion, res)
// ...
}
Source: internal/bodyprocessors/json.go, lines 81-94.
For every object level, readItems appends a literal dot followed by the unescaped property name:
prevParentLength := len(objKey)
objKey = append(objKey, '.')
if key.Type == gjson.String {
objKey = append(objKey, key.Str...)
}
Source: internal/bodyprocessors/json.go, lines 111-120.
Scalar values are stored in the map using the resulting flattened string:
res[string(objKey)] = val
Source: internal/bodyprocessors/json.go, lines 122-145.
This produces a collision:
Nested property: {"account":{"role":"ATTACK"}}
Generated Coraza key: json.account.role
Literal dotted key: {"account.role":"SAFE"}
Generated Coraza key: json.account.role
Because both values use the same Go map key, the property appearing later in the JSON document overwrites the earlier value. The malicious value no longer exists anywhere in the ordinary ARGS_POST collection.
ProcessRequest subsequently copies only the final map entries into ARGS_POST:
data, err := readJSON(ss, bpo.RequestBodyRecursionLimit)
for key, value := range data {
col.SetIndex(key, 0, value)
}
Source: internal/bodyprocessors/json.go, lines 29-39.
The JSON remains valid, so Coraza does not set REQBODY_ERROR. A normal backend parser does not flatten property names and therefore keeps the nested account.role value separate from the literal top-level "account.role" property.
Coraza's recommended configuration enables JSON processing, and OWASP CRS rules inspect the generated argument collection. This makes the issue reachable in a standard Coraza and CRS deployment.
The bypass was reproduced against CRS v4.25 under all of the following…
- Record
GHSA-5gj4-9gm7-2fx2- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N - Weakness
- CWE-20, CWE-436
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-vmwg-gmpq-826x
6.9
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot...
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot-separated ARGS_POST names without escaping literal dots, so distinct properties collide. Unauthenticated attackers can add a later dotted property such as account.role that overwrites a malicious nested value, hiding SQL injection payloads from OWASP CRS rules while backends still receive them.
- Record
GHSA-vmwg-gmpq-826x- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
NVD
6.9
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot-separated ARGS_POST names without escaping literal dots, so distinct properties collide. Unauthenticated attackers can add a later dotted property such as account.role that overwrites a malicious nested value, hiding SQL injection payloads from OWASP CRS rules while backends still receive them.
- Record
CVE-2026-114099- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
OSV
6.9
Coraza 3.0.0 before 3.8.1 WAF Bypass via JSON Key Collision
Coraza from 3.0.0 before 3.8.1 has a JSON body processor that flattens nested properties into dot-separated ARGS_POST names without escaping literal dots, so distinct properties collide. Unauthenticated attackers can add a later dotted property such as account.role that overwrites a malicious nested value, hiding SQL injection payloads from OWASP CRS rules while backends still receive them.
- Record
CVE-2026-114099- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N - Weakness
- CWE-20
- Updated
- 2026-11-02
OSVGHSA-5gj4-9gm7-2fx2
5.8
Coraza body processor has a JSON key collision that allows unauthenticated attackers to bypass OWASP CRS inspection
Summary
Coraza's JSON body processor converts nested JSON properties into dot-separated ARGS_POST names without escaping dots contained in literal property names. Two distinct JSON properties can therefore collapse into the same Coraza variable
An unauthenticated attacker can place a malicious value in a nested property and then overwrite only Coraza's representation with a harmless dotted property:
{
"account": {
"role": "1' OR '1'='1"
},
"account.role": "safe"
}
Coraza stores both properties as ARGS_POST:json.account.role; the later value safe replaces the SQL-injection value. Standard backend JSON parsers preserve the two distinct properties and expose the malicious nested value as account.role.
This bypasses the complete current OWASP Core Rule Set (CRS) for the hidden value. In the supplied control-pair PoC, CRS v4.25 blocks the nested SQL-injection value with rule 949110. Adding the dotted decoy makes the same attack pass with no interruption, while Go's standard JSON parser still returns the malicious nested value.
Details
The affected component is the JSON body processor in internal/bodyprocessors/json.go.
readJSON creates a single map[string]string and begins every generated path with json:
func readJSON(s string, maxRecursion int) (map[string]string, error) {
res := make(map[string]string)
key := []byte("json")
json := gjson.Parse(s)
err := readItems(json, key, maxRecursion, res)
// ...
}
Source: internal/bodyprocessors/json.go, lines 81-94.
For every object level, readItems appends a literal dot followed by the unescaped property name:
prevParentLength := len(objKey)
objKey = append(objKey, '.')
if key.Type == gjson.String {
objKey = append(objKey, key.Str...)
}
Source: internal/bodyprocessors/json.go, lines 111-120.
Scalar values are stored in the map using the resulting flattened string:
res[string(objKey)] = val
Source: internal/bodyprocessors/json.go, lines 122-145.
This produces a collision:
Nested property: {"account":{"role":"ATTACK"}}
Generated Coraza key: json.account.role
Literal dotted key: {"account.role":"SAFE"}
Generated Coraza key: json.account.role
Because both values use the same Go map key, the property appearing later in the JSON document overwrites the earlier value. The malicious value no longer exists anywhere in the ordinary ARGS_POST collection.
ProcessRequest subsequently copies only the final map entries into ARGS_POST:
data, err := readJSON(ss, bpo.RequestBodyRecursionLimit)
for key, value := range data {
col.SetIndex(key, 0, value)
}
Source: internal/bodyprocessors/json.go, lines 29-39.
The JSON remains valid, so Coraza does not set REQBODY_ERROR. A normal backend parser does not flatten property names and therefore keeps the nested account.role value separate from the literal top-level "account.role" property.
Coraza's recommended configuration enables JSON processing, and OWASP CRS rules inspect the generated argument collection. This makes the issue reachable in a standard Coraza and CRS deployment.
The bypass was reproduced against CRS v4.25 under all of the following…
- Record
GHSA-5gj4-9gm7-2fx2- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N - Weakness
- CWE-20, CWE-436
- Updated
- 2026-11-02
OSVGO-2026-6692 No score
Coraza body processor has a JSON key collision that allows unauthenticated attackers to bypass OWASP CRS inspection in github.com/corazawaf/coraza
Coraza body processor has a JSON key collision that allows unauthenticated attackers to bypass OWASP CRS inspection in github.com/corazawaf/coraza
- Record
GO-2026-6692- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/corazawaf/coraza/v3Go |
3.0.0 up to 3.8.1 | 3.8.1 |
github.com/corazawaf/corazaGo |
All versions | None known |
github.com/corazawaf/coraza/v2Go |
All versions | None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-114099 is a medium vulnerability (CVSS 6.9) in Corazawaf Coraza, published October 8, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.29%, the 22nd percentile. Fixed in github.com/corazawaf/coraza/v3 3.8.1.
References
github.com/corazawaf/coraza/security/advisories/GHSA-5gj4-9gm7-2fx2
vulncheck.com/advisories/coraza-3.0.0-before-3.8.1-waf-bypass-via-json-key-collision
github.com/corazawaf/coraza/commit/52af139cab5ad10c5cb0152a161063b523907bdf
github.com/corazawaf/coraza/commit/5f577a548aeb9ca836122df4258f93ef6cfab38a
github.com/corazawaf/coraza/commit/cae3c7407e7b84372c207033de03f15f89bf351a
github.com/corazawaf/coraza/releases/tag/v3.8.1
Left out here: the rest of 2 source descriptions. The JSON record has them.