Skip to content

Commit d0aed74

Browse files
fix: use length-check + ct_eq for constant-time auth comparison (#153)
Replace zero-padded constant-time comparison with the canonical pattern: check lengths first (non-constant-time, acceptable since length leakage doesn't help brute-force a high-entropy token), then ct_eq on equal-length slices. This avoids a theoretical null-byte false-positive in the padding approach. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b1c837b commit d0aed74

1 file changed

Lines changed: 5 additions & 7 deletions

File tree

src/mcp.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -943,19 +943,17 @@ pub async fn run_http(
943943
}
944944

945945
// Constant-time comparison to prevent timing side-channels.
946-
// Pad to equal length so ct_eq compares all bytes even when lengths differ.
946+
// Length check is non-constant-time but leaking length doesn't
947+
// help brute-force a high-entropy token.
947948
if let Some(auth) = req.headers().get("authorization") {
948949
if let Ok(auth_str) = auth.to_str() {
949950
let expected_header = format!("Bearer {}", expected);
950951
use subtle::ConstantTimeEq;
951952
let expected_bytes = expected_header.as_bytes();
952953
let provided_bytes = auth_str.as_bytes();
953-
let len = expected_bytes.len().max(provided_bytes.len());
954-
let mut e = vec![0u8; len];
955-
let mut p = vec![0u8; len];
956-
e[..expected_bytes.len()].copy_from_slice(expected_bytes);
957-
p[..provided_bytes.len()].copy_from_slice(provided_bytes);
958-
if e.ct_eq(&p).into() {
954+
if expected_bytes.len() == provided_bytes.len()
955+
&& expected_bytes.ct_eq(provided_bytes).into()
956+
{
959957
return next.run(req).await;
960958
}
961959
}

0 commit comments

Comments
 (0)