Skip to content

Commit ac14c2e

Browse files
fix(l7): reject requests with both CL and TE headers in inference parser (CWE-444)
The CL/TE desynchronisation guard added in NVIDIA#663 for the REST path was not applied to the inference request parser. A request containing both Content-Length and Transfer-Encoding headers could be interpreted differently by the proxy and the upstream server, enabling HTTP request smuggling (CWE-444, RFC 7230 Section 3.3.3). Add the same rejection check and two tests mirroring the REST parser coverage. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
1 parent 0ac1fbd commit ac14c2e

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

crates/openshell-sandbox/src/l7/inference.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ pub fn try_parse_http_request(buf: &[u8]) -> ParseResult {
164164
}
165165
}
166166

167+
if is_chunked && has_content_length {
168+
return ParseResult::Invalid(
169+
"request contains both Transfer-Encoding and Content-Length headers"
170+
.to_string(),
171+
);
172+
}
173+
167174
let (body, consumed) = if is_chunked {
168175
let Some((decoded_body, consumed)) = parse_chunked_body(buf, body_start) else {
169176
return ParseResult::Incomplete;
@@ -608,4 +615,37 @@ mod tests {
608615
ParseResult::Invalid(_)
609616
));
610617
}
618+
619+
// ---- SEC-009: CL/TE desynchronisation ----
620+
621+
/// Reject requests with both Content-Length and Transfer-Encoding to
622+
/// prevent CL/TE request smuggling (RFC 7230 Section 3.3.3).
623+
#[test]
624+
fn reject_dual_content_length_and_transfer_encoding() {
625+
let request = b"POST /v1/chat/completions HTTP/1.1\r\nHost: x\r\nContent-Length: 5\r\nTransfer-Encoding: chunked\r\n\r\n";
626+
assert!(
627+
matches!(
628+
try_parse_http_request(request),
629+
ParseResult::Invalid(reason)
630+
if reason.contains("Transfer-Encoding")
631+
&& reason.contains("Content-Length")
632+
),
633+
"Must reject request with both CL and TE"
634+
);
635+
}
636+
637+
/// Same rejection regardless of header order.
638+
#[test]
639+
fn reject_dual_transfer_encoding_and_content_length() {
640+
let request = b"POST /v1/chat/completions HTTP/1.1\r\nHost: x\r\nTransfer-Encoding: chunked\r\nContent-Length: 5\r\n\r\n";
641+
assert!(
642+
matches!(
643+
try_parse_http_request(request),
644+
ParseResult::Invalid(reason)
645+
if reason.contains("Transfer-Encoding")
646+
&& reason.contains("Content-Length")
647+
),
648+
"Must reject request with both TE and CL"
649+
);
650+
}
611651
}

0 commit comments

Comments
 (0)