Every CVE Search/ Get API key

CVE-2026-114099

Coraza 3.0.0 before 3.8.1 WAF Bypass via JSON Key Collision

6.9 MediumFix available

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

0.29%Up 0.1 points since Oct 21, 2026
90%50%10%1%

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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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 MediumCVSS: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

Affected packages
PackageAffectedFixed
github.com/corazawaf/coraza/v3
Go
3.0.0 up to 3.8.1
3.8.1
github.com/corazawaf/coraza
Go
All versions None known
github.com/corazawaf/coraza/v2
Go
All versions None known

History

History
RecordedChangedSources
first indexedCVE 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

Show 5 moreShow less
This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open