Skip to main content

Coraza WAF EUVDEUVD-2026-97828

| CVE-2026-41508 MEDIUM
Improper Input Validation (CWE-20)
2026-10-06 https://github.com/corazawaf/coraza GHSA-r3rm-qphw-hh76
5.8
CVSS 3.1 · Vendor: https://github.com/corazawaf/coraza
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Send truncated multipart/form-data request
  2. Delivery
    Parser hits io.ErrUnexpectedEOF, swallowed silently
  3. Exploit
    MULTIPART_STRICT_ERROR stays 0, rules 200002/200003 don't fire
  4. Execution
    Request passes WAF as benign
  5. Impact
    Backend's permissive parser extracts smuggled payload

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V2 - Validation and Business Logic Input validation, allowlisting
Exploitation Conditions

Requires Coraza v3.4.0-3.7.0 deployed inline as a WAF with SecRuleEngine On and SecRequestBodyAccess On, AND the operator relying on the recommended coraza.conf rules 200002 (REQBODY_ERROR) / 200003 (MULTIPART_STRICT_ERROR) as the multipart parser-disagreement defense. The trigger is a multipart/form-data request whose body ends prematurely so the Go reader raises io.ErrUnexpectedEOF - e.g. a missing closing boundary or a mid-part cutoff (name="x"\r\n\r\nabc). No authentication is needed (PR:N) and exploitation works against the default recommended configuration. LIMITING FACTORS: the bypass only neutralizes a defense-in-depth rule, so actual compromise additionally requires a backend multipart parser that disagrees with Go's and extracts the smuggled content; deployments not using rule 200003, or those intentionally running SecRequestBodyLimitAction ProcessPartial, are affected differently and may accept truncated bodies by design.

Impact

This is a defense-in-depth control bypass in the OWASP Coraza WAF engine, and the signals point to a real-but-moderate priority rather than an urgent emergency. The CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N, base 5.8) is internally consistent with the description: a remote, unauthenticated attacker sends a crafted multipart body over the network with low complexity and no user interaction, and the scope change (S:C) plus integrity-only impact (I:L) correctly reflect that the harm lands on the protected backend, not on Coraza itself. No EPSS score was provided (MISSING), the CVE is NOT in CISA KEV, and there is no evidence of active exploitation; however, the public GHSA advisory documents a concrete proof-of-concept (three curl cases showing HTTP 200 where 400 is expected), so working reproduction steps are public. The key nuance that lowers real-world severity: this flaw does not directly compromise anything on its own - it silently clears the MULTIPART_STRICT_ERROR flag so recommended rules 200002/200003 fail to fire, which only matters if (a) the operator relies on those recommended rules as their multipart-evasion defense and (b) a downstream parser (PHP/Node/Java/etc.) actually disagrees with Go's mime/multipart reader and extracts the smuggled content. So a CVSS of 5.8 with a documented PoC but no KEV/EPSS signal is best read as 'targeted, conditional WAF-evasion enabler' rather than mass-exploitable RCE.

Exploit ScenarioDerived

An attacker submits a multipart/form-data POST whose body is deliberately truncated - for example two parts with no closing boundary, or a mid-part cutoff - so Coraza's parser hits io.ErrUnexpectedEOF. Because v3.4.0-3.7.0 swallow that error without setting MULTIPART_STRICT_ERROR, recommended rules 200003 and 200002 never fire and the request is passed through (HTTP 200), letting a smuggled field or payload reach a backend whose more permissive multipart parser still extracts it. A public PoC in the GHSA advisory demonstrates the bypass with real curl requests and confirms transaction.variables.multipartStrictError == 0.

This Month Plan within 30 days. Why: MEDIUM severity (CVSS 4.0-6.9).
Patch available 0.5% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Oct 06, 2026

Defense-in-depth bypass in Coraza WAF 3.4.0 through 3.7.0 causes the multipart body processor to silently swallow io.ErrUnexpectedEOF, so a truncated multipart/form-data request neither sets MULTIPART_STRICT_ERROR nor returns a request-body error, and the two canonical defensive rules shipped in coraza.conf-recommended (200003 MULTIPART_STRICT_ERROR and 200002 REQBODY_ERROR) fail open. Remote unauthenticated attackers (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N, 5.8) can send a body that omits the closing boundary or cuts off mid-part and have it processed as if well-formed, neutralizing the parser-disagreement catch-all and enabling multipart smuggling or CRS evasion chains against backends whose multipart parser disagrees with Go's mime/multipart reader. No active exploitation is confirmed (not in CISA KEV), though the vendor advisory publishes a working reproduction proof-of-concept and the vendor-released fix is v3.8.0.

RemediationAI

Vendor-released patch: upgrade to Coraza v3.8.0 (https://github.com/corazawaf/coraza/releases/tag/v3.8.0), which contains commit f94c81bec209f658120c418448d0590a549b71df adding the missing v.MultipartStrictError().(*collections.Single).Set("1") calls at all three sites in internal/bodyprocessors/multipart.go and regression tests for truncated bodies; there is no configuration-only fix that restores the invariant. If immediate upgrade is impossible, the most direct compensating control is to back-port that two-line-per-site change into the vendored module and rebuild, since the patch preserves PR #1453's ProcessPartial semantics (trade-off: you must maintain a local fork until the upgrade lands), or temporarily pin to a pre-3.4.0 release where io.ErrUnexpectedEOF returns err and rule 200002 fires (trade-off: loses SecRequestBodyLimitAction ProcessPartial support and older feature sets). Operators relying solely on the recommended rules 200002/200003 should add an independent multipart framing validation layer in front of or behind Coraza - for example a reverse proxy that verifies the closing boundary and Content-Length/body consistency, or backend-side strict multipart validation - because rule 200003 is the only defense-in-depth rule for multipart in coraza.conf-recommended and offers no secondary signal once bypassed. Deployments intentionally running SecRequestBodyLimitAction ProcessPartial, which accept truncated bodies by design, should pair the engine fix by scoping rule 200003 or downgrading it to detection-only for the legitimate truncation case; note that doing so re-widens exposure unless the truncation is correlated with an actual configured request-body-limit hit. Consult the advisory at https://github.com/corazawaf/coraza/security/advisories/GHSA-r3rm-qphw-hh76 for the authoritative fix details.

Affected VersionsENISA

coraza 3.4.0, < 3.8.0

Affected Packages

go github.com/corazawaf/coraza no fix
go github.com/corazawaf/coraza/v2 no fix
go github.com/corazawaf/coraza/v3 fix: 3.8.0
euvd coraza_3_4_0 fix: 3.8.0

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 4 packages in go, euvd

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

Coraza is a Go-based WAF engine and the reference OWASP Core Rule Set implementation for Go (CPE pkg:go/github.com_corazawaf_coraza_v3); the flaw sits in internal/bodyprocessors/multipart.go, the component that reads multipart/form-data bodies into ARGS via Go's mime/multipart reader. CWE-20 (Improper Input Validation): three error branches (filesystem-backed file branch around lines 71-77, TinyGo discard branch around lines 82-88, and the field branch around lines 102-113) special-case io.ErrUnexpectedEOF only to suppress the fatal return, setting seenUnexpectedEOF or breaking out of the loop without setting the multipart-strict-error transaction variable. The processor therefore returns nil for any prematurely terminated body, leaving MULTIPART_STRICT_ERROR at its initial value 0 and never propagating a request-body error. This is a regression introduced by PR #1453 (commit 3347961b, merged 2026-03-06, first shipped in v3.4.0), which legitimately needed to tolerate truncation for SecRequestBodyLimitAction ProcessPartial so partially received parts still surface; it over-corrected by silencing the operator-visible strict-error flag rather than keeping the non-fatal break/flag pair. Every other error path in the function correctly sets MULTIPART_STRICT_ERROR before returning, confirming this is an inconsistency rather than a systemic parser failure, and the upstream fix commit f94c81be adds exactly three one-line flag setters plus regression tests asserting the flag is raised for truncated payloads. The impact class is parser-inconsistency evasion: rule 200003 is the only recommended catch-all for cases where Coraza's Go parser and the backend parser (PHP, Node, Java, libmodsecurity) disagree about field boundaries.

Know when Go gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/corazawaf/coraza) PRIMARY 5.8 MEDIUM
AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N
vuln.today AI 5.8 MEDIUM

Remote unauthenticated crafted multipart request (AV:N/PR:N/UI:N) with deterministic crafting (AC:L); only integrity of the protected downstream system is affected (S:C, I:L), with no confidentiality or availability impact.

3.1 AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:N

Primary rating from Vendor (https://github.com/corazawaf/coraza).

CVSS VectorVendor: https://github.com/corazawaf/coraza

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Confidentiality
None
Integrity
Low
Availability
None

DescriptionCVE.org

Root Cause

File: internal/bodyprocessors/multipart.go (since commit 3347961b, PR #1453 *"feat: ignore unexpected EOF in MIME multipart request body processor"*, merged 2026-03-06, first shipped in v3.4.0).

The multipart body processor treats io.ErrUnexpectedEOF as a benign condition. Three sites are affected; all mishandle the error the same way.

File branch, filesystem-backed (lines 71-77)

go
sz, err := io.Copy(temp, p)
if err != nil {
    if !errors.Is(err, io.ErrUnexpectedEOF) {
        v.MultipartStrictError().(*collections.Single).Set("1")
        return err
    }
    seenUnexpectedEOF = true     // <-- flag never set for UnexpectedEOF
}

File branch, TinyGo path (lines 82-88)

go
sz, err := io.Copy(io.Discard, p)
if err != nil {
    if !errors.Is(err, io.ErrUnexpectedEOF) {
        v.MultipartStrictError().(*collections.Single).Set("1")
        return err
    }
    seenUnexpectedEOF = true     // <-- same gap
}

Field branch (lines 102-113)

go
data, err := io.ReadAll(p)
if err != nil {
    if !errors.Is(err, io.ErrUnexpectedEOF) {
        v.MultipartStrictError().(*collections.Single).Set("1")
        return err
    }
}
...
if errors.Is(err, io.ErrUnexpectedEOF) {
    break                         // <-- exits loop with no flag set
}

The function then returns nil at line 116 for any body that ended prematurely. Consequences:

  1. MULTIPART_STRICT_ERROR stays at its initial value 0.
  2. REQBODY_ERROR is not propagated either (since ProcessRequest returns nil).
  3. Neither of the two canonical defensive rules shipped in coraza.conf-recommended fires:
conf
   SecRule REQBODY_ERROR "!@eq 0" "id:200002,phase:2,deny,status:400,..."
   SecRule MULTIPART_STRICT_ERROR "!@eq 0" "id:200003,phase:2,deny,status:400,..."

All other error branches in the same function (lines 27, 48, 66, 84, 104) correctly set MULTIPART_STRICT_ERROR before returning; this is an inconsistency introduced in #1453, not a systemic issue.

Context - why the error is swallowed

PR #1453 was introduced to support SecRequestBodyLimitAction ProcessPartial: when a body is cut off because it hit the configured request-body limit, the parser should still surface the parts it did receive. The PR legitimately needs to avoid return err on ErrUnexpectedEOF. But it also silenced the strict-error flag, which is the wrong compromise - the flag is exactly how operators observe that something was incomplete. The fix should keep the non-fatal break and still set MULTIPART_STRICT_ERROR, letting the operator decide (via rule 200003 or their own policy) whether partial processing is acceptable.

Impact

Rule 200003 is Coraza's blanket defense against multipart parser-inconsistency evasions - attack classes where the body is crafted so Coraza's Go mime/multipart reader and the backend's multipart parser (PHP, Node, Java, legacy libmodsecurity, etc.) disagree about where fields start or end. The rule fails-closed on *any* malformed body, so the operator does not need to enumerate every parser-disagreement trick. That defense is now void for any evasion that also truncates the body.

Examples of what becomes reachable:

  • Smuggling a second field past the truncation boundary that the backend's more permissive parser still extracts.
  • Hiding payload bytes after a deliberately malformed Content-Disposition header that the Go parser refuses but the backend accepts.
  • Generic CRS evasion chains that depend on rule 200003 as a catch-all.

The fix is tiny and low-risk. The impact is disproportionately large because rule 200003 is the *only* defense-in-depth rule for multipart in the recommended config - there is no secondary signal.

Proof of Concept

Start a Coraza-wrapped HTTP server shipping the canonical defensive rules from coraza.conf-recommended:

conf
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQBODY_ERROR "!@eq 0" \
    "id:200002,phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.'"
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
    "id:200003,phase:2,t:none,log,deny,status:400,msg:'Multipart strict validation failed.'"

Three real-curl requests against the listener:

| Body | Expected (with rule 200003) | Observed |

|

|---|---|---|---| | 1 | Well-formed field1=benign + closing boundary | HTTP 200 | HTTP 200 (baseline) | | 2 | Two parts, no closing boundary (...MALFORMED_NO_TRAILING_BOUNDARY) | HTTP 400 | HTTP 200 | | 3 | Mid-part cutoff: name="x"\r\n\r\nabc (no \r\n, no boundary) | HTTP 400 | HTTP 200 | Server-side match log is empty for cases 2 and 3: neither rule 200002 nor rule 200003 fires. Example (case 2):

--PoCBoundary12345\r\n
Content-Disposition: form-data; name="field1"\r\n\r\n
benign\r\n
--PoCBoundary12345\r\n
Content-Disposition: form-data; name="truncated"\r\n\r\n
MALFORMED_NO_TRAILING_BOUNDARY

→ HTTP 200, no audit record, transaction.variables.multipartStrictError == 0.

Mitigation

A two-line change per site in internal/bodyprocessors/multipart.go:

go
if errors.Is(err, io.ErrUnexpectedEOF) {
    v.MultipartStrictError().(*collections.Single).Set("1")
    seenUnexpectedEOF = true   // keep existing break semantics
}

Apply at the three sites (lines 71-77, 82-88, 102-113 in the current code). No change to the return err control flow is needed - the fix only adds the flag-setter alongside the existing seenUnexpectedEOF = true / break path. PR #1453's ProcessPartial goal is preserved.

Operators running in ProcessPartial mode who intentionally allow truncated bodies should pair this with a config-level change (downgrade rule 200003 to detection-only, or scope it with a secondary check on whether SecRequestBodyLimit was actually hit). The engine change above is safe by default - it restores the invariant that malformed multipart always raises MULTIPART_STRICT_ERROR.

Affected versions

Introduced in PR #1453 (commit 3347961b, merged 2026-03-06). First released in v3.4.0 and still present on main at 599ae64a.

Affected: >= 3.4.0, <= 3.7.0.

Releases prior to v3.4.0 returned err on io.ErrUnexpectedEOF and so REQBODY_ERROR would propagate via rule 200002 even if MULTIPART_STRICT_ERROR was not set - a different (arguably stricter) behavior that did not exhibit this bypass.

References

  • internal/bodyprocessors/multipart.go lines 70-113
  • coraza.conf-recommended rule id:200003 (MULTIPART_STRICT_ERROR)
  • PR #1453 - introduction of ErrUnexpectedEOF swallowing
  • coraza.conf-recommended rule id:200002 (REQBODY_ERROR) - also not raised because ProcessRequest returns nil

Threat Intelligence Overview

EPSS Score
0.5%
Top 59% exploitable
Prevalence
Medium
OWASP WAF library adopted via Caddy/Traefik plugins; moderate production footprint
Threat Intel
1
1 source
Data Quality
5 sources
Confidence: Medium

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity MEDIUM
CISA KEV No
Public POC No
EPSS 0.5%
Patch available Yes
Active threat No
Deciding rule
MEDIUM severity (CVSS 4.0-6.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Open
Automatable· derived
Yes
Human Impact· derived
Medium

Priority Score

29
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +29
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

More in Go

View all
CVE-2023-44487 HIGH POC
7.5 Oct 10

Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour

CVE-2016-5386 HIGH
8.1 Jul 19

The net/http package in Go through 1.6 does not attempt to address RFC 3875 section 4.1.18 namespace conflicts and there

CVE-2025-68121 CRITICAL POC
10.0 Feb 05

Critical certificate validation bypass in Go crypto/tls during session resumption. If ClientCAs or RootCAs fields are mu

CVE-2019-14809 CRITICAL POC
9.8 Aug 13

net/url in Go before 1.11.13 and 1.12.x before 1.12.8 mishandles malformed hosts in URLs, leading to an authorization by

CVE-2026-90942 CRITICAL POC
9.3 Sep 14

Casdoor through 4.4.0 exposes its instance-wide built-in JWT signing private key unmasked through the /api/get-certs and

CVE-2026-101090 CRITICAL POC
9.3 Sep 27

Host header injection in Nezha 2.2.3's OAuth2 redirect endpoint (/api/v1/oauth2/{provider}) allows an unauthenticated re

CVE-2026-78428 HIGH POC
8.8 Sep 17

Session cross-wiring in SUSE NeuVector before 5.6.1 allows an unauthenticated remote attacker to obtain another user's a

CVE-2026-92791 HIGH POC
8.7 Sep 16

Unauthenticated path traversal in Uber Kraken through 0.1.29 allows remote attackers to read files outside the configure

CVE-2018-7187 HIGH POC
8.8 Feb 16

The "go get" implementation in Go 1.9.4, when the -insecure command-line option is used, does not validate the import pa

CVE-2026-16651 HIGH POC
8.7 Sep 21

Denial of service in Temporal Server allows an authenticated caller holding at least namespace read permission to crash

CVE-2026-82405 HIGH POC
8.7 Sep 23

Account takeover in Klever-Go's KleverUpdateAccountPermission built-in (all versions prior to 1.7.20) allows an attacker

CVE-2026-82409 HIGH POC
8.4 Sep 23

Maliciously crafted on-chain account names processed by Klever-Go prior to 1.7.20 are spliced into Elasticsearch _bulk r

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy