harden(ft,auth,net): cap transfers/frames, evict stale SRP, distrust XFF
CI / rust client (hh) (macos-latest) (push) Has been cancelled
CI / rust client (hh) (ubuntu-latest) (push) Has been cancelled
CI / rust coverage (push) Has been cancelled
CI / python server (3.10) (push) Has been cancelled
CI / python server (3.11) (push) Has been cancelled
CI / python server (3.12) (push) Has been cancelled
CI / headless e2e smoke (push) Has been cancelled
CI / dependency audit (push) Has been cancelled
CI / secret scanning (push) Has been cancelled
CI / rust client (hh) (macos-latest) (push) Has been cancelled
CI / rust client (hh) (ubuntu-latest) (push) Has been cancelled
CI / rust coverage (push) Has been cancelled
CI / python server (3.10) (push) Has been cancelled
CI / python server (3.11) (push) Has been cancelled
CI / python server (3.12) (push) Has been cancelled
CI / headless e2e smoke (push) Has been cancelled
CI / dependency audit (push) Has been cancelled
CI / secret scanning (push) Has been cancelled
M1: enforce the declared transfer size (clamped to MAX_SIZE) on chunk receipt in both the Rust and Python clients — a malicious sender can no longer grow the receive buffer unboundedly. M2: only honor X-Forwarded-For when TRUST_PROXY is set, so a direct client can't spoof a source IP to dodge the per-IP rate limiter. M3: evict unverified SRP sessions after a 60s TTL on each new handshake, preventing half-finished auths from exhausting memory. M4: drop WS frames larger than 256 KB before they hit the store or broadcast, bounding per-message memory and flood blast radius. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+19
-1
@@ -573,9 +573,27 @@ fn handle_ft(
|
||||
}
|
||||
}
|
||||
ft::Ft::Chunk { id, data } => {
|
||||
// Enforce the declared size (clamped to MAX_SIZE) on receipt — a
|
||||
// malicious sender can lie about `size` or just keep streaming, so
|
||||
// never let an accepted transfer grow its buffer past the cap.
|
||||
let mut overflow = false;
|
||||
if let Some(t) = app.transfers.get_mut(&id) {
|
||||
if t.accepted {
|
||||
t.buf.extend_from_slice(&data);
|
||||
let cap = (t.meta.size as usize).min(ft::MAX_SIZE);
|
||||
if t.buf.len() + data.len() > cap {
|
||||
overflow = true;
|
||||
} else {
|
||||
t.buf.extend_from_slice(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if overflow {
|
||||
if let Some(t) = app.transfers.remove(&id) {
|
||||
app.err(format!(
|
||||
"{} — transfer exceeds declared size (max {}), aborted",
|
||||
t.meta.name,
|
||||
ft::human((t.meta.size as usize).min(ft::MAX_SIZE))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user