Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions crates/kawa/RUSTSEC-0000-0000.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
```toml
[advisory]
id = "RUSTSEC-0000-0000"
package = "kawa"
date = "2026-07-15"
url = "https://github.com/CleverCloud/kawa/pull/19"
keywords = ["http", "parsing", "request-smuggling"]
cvss = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"

[versions]
patched = [">= 0.7.0"]
```

# Lenient `Transfer-Encoding` parsing in `kawa` allows HTTP request smuggling

`kawa`'s HTTP/1 header parser selected chunked framing using a suffix-only comparison on the
raw `Transfer-Encoding` value, without trimming optional whitespace (OWS) and without
requiring `chunked` to be the final transfer-coding:

```rust
const CHUNKED: &[u8] = b"chunked";
if val.len() >= CHUNKED.len()
&& compare_no_case(&val[val.len() - CHUNKED.len()..], CHUNKED)
```

Values such as `chunked\t`, `chunked ` (trailing space), and `chunked,identity` therefore did
not select chunked framing. When such a request also carried a `Content-Length`, `kawa` framed
the message by `Content-Length` and forwarded the `Transfer-Encoding` header unchanged, instead
of rejecting the message as RFC 9112 §6.3 requires.

A downstream server that resolves `Transfer-Encoding` correctly (trimming OWS per RFC 9110
§5.6.3) then frames the same message as chunked. Front end and back end disagree on the message
boundary, which is a CL.TE desynchronization: an attacker can prepend arbitrary bytes to the
next request on a reused back end connection, bypassing any authentication, ACL, or rate
limiting enforced only at the proxy.

To be affected, `kawa` must be used to parse HTTP/1 requests that are forwarded to another HTTP
implementation whose `Transfer-Encoding` handling is stricter. Backends observed to honor the
obfuscated header include Go `net/http`, Puma, `uvicorn --http h11`, and Hypercorn.

This is a regression of [sozu-proxy/sozu#726](https://github.com/sozu-proxy/sozu/issues/726),
fixed in 2021 by sozu PR #739 and lost in the rewrite onto `kawa`.

## Remediation

Upgrade to `kawa` 0.7.0 or later, which trims OWS, requires `chunked` to be the final
transfer-coding, and rejects a request whose `Transfer-Encoding` is present but does not end in
`chunked` ([PR #19](https://github.com/CleverCloud/kawa/pull/19),
[PR #21](https://github.com/CleverCloud/kawa/pull/21)).

Users of `sozu` should upgrade to 2.2.0 or later, which depends on `kawa` 0.7.1. `sozu` 2.1.1
and earlier bundle the affected `kawa` 0.6.8.

Reported by Aymane Mazguiti (unclej4ck).