actix/actix-web · error · io::Error
Invalid character in chunk extension
Error message
Invalid character in chunk extension
What it means
io::Error(InvalidInput, "Invalid character in chunk extension") (chunked.rs:105-108) is returned by read_extension when a chunk extension (the part after ';' on the size line) contains a control character outside the permitted set. Allowed: printable ASCII plus tab; rejected: 0x00-0x08, 0x0a-0x1f, 0x7f. The hrs_chunk_extension_invalid test (chunked.rs:385-404) reproduces it.
Source
Thrown at actix-http/src/h1/chunked.rs:105
}
fn read_size_lws(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) {
// LWS can follow the chunk size, but no more digits can come
b'\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),
b';' => Poll::Ready(Ok(ChunkedState::Extension)),
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
_ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk size linear white space",
))),
}
}
fn read_extension(rdr: &mut BytesMut) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) {
b'\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),
// strictly 0x20 (space) should be disallowed but we don't parse quoted strings here
0x00..=0x08 | 0x0a..=0x1f | 0x7f => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid character in chunk extension",
))),
_ => Poll::Ready(Ok(ChunkedState::Extension)), // no supported extensions
}
}
fn read_size_lf(rdr: &mut BytesMut, size: u64) -> Poll<Result<ChunkedState, io::Error>> {
match byte!(rdr) {
b'\n' if size > 0 => Poll::Ready(Ok(ChunkedState::Body)),
b'\n' if size == 0 => Poll::Ready(Ok(ChunkedState::EndCr)),
_ => Poll::Ready(Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid chunk size LF",
))),
}
}
fn read_body(View on GitHub (pinned to 937960ca67)
Solutions
- Sanitise or omit chunk extensions; they are optional and ignored by actix.
- Reject or normalise Transfer-Encoding at a front proxy.
- Update the peer encoder to quote/escape extension values per RFC 7230 §4.1.1.
Defensive patterns
Strategy: try-catch
Try / catch
// Reject requests whose chunked body contains invalid extension bytes.
use actix_http::error::PayloadError;
match payload.next().await {
Some(Err(PayloadError::Io(e))) if e.kind() == io::ErrorKind::InvalidInput => {
return HttpResponse::BadRequest().finish();
}
_ => {}
} Prevention
- Omit chunk extensions unless you actually need them; actix ignores them anyway.
- Reject HTTP Request Smuggling-style payloads at the edge.
- Ensure proxies do not inject control bytes into extensions.
When it happens
Trigger: A chunk size line like '2;x\nx\r\n' places a raw LF inside the extension, which read_extension flags. Quoted-string extension values with spaces are tolerated, but raw control bytes are not.
Common situations: A client injecting unescaped control bytes into a chunk extension, or an HTTP Request Smuggling attempt exploiting extension parsing.
Related errors
- Invalid chunk size line: Size is too big
- Invalid chunk size line: Invalid Size
- Invalid chunk size linear white space
- Invalid chunk size LF
- Invalid chunk body CR
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/53941aa976395a82.json.
Report an issue: GitHub.