fix(security): close S3 (arg-injection), S4 (presence-name), S1 (panic-slice)
Three findings from the first security pass: - S3 (Medium): the peer-supplied screen-share ticket was passed to pixelpass as the first positional CLI arg with no end-of-options guard, so a ticket starting with `-`/`--` could be reinterpreted as a flag (argument injection). New pure `viewer_args()` puts flags first, then a `--` guard, then the ticket positionally; spawn_viewer uses it. +2 tests. - S4 (Medium): peer presence display-names (gossip `Announce`, untrusted and spoofable) were rendered unsanitized/unbounded, unlike the chat path. New `sanitize::sanitize_name` strips bidi/zero-width format chars + control chars, collapses whitespace, and caps at 48 chars; applied at the gossip ingest point so every consumer gets a safe value. +4 tests. - S1 (Low): `&id[..8]` byte-slices could panic on a short/non-ASCII id. New panic-free `short_id()` (char-based take) replaces both slices. +1 test. 158 lib tests (was 151), clippy --all-targets clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -144,7 +144,11 @@ impl RoomState for IrohGossipState {
|
||||
crate::log_msg(&format!("Gossip Event::Received from author={:?}, payload={:?}", payload.author, payload.msg));
|
||||
|
||||
match payload.msg {
|
||||
GossipMessage::Announce(state) => {
|
||||
GossipMessage::Announce(mut state) => {
|
||||
// Presence names are untrusted (and author-
|
||||
// spoofable): sanitize at ingest so every
|
||||
// consumer gets a safe value (security S4).
|
||||
state.name = crate::sanitize::sanitize_name(&state.name);
|
||||
let (is_new, state_changed) = {
|
||||
let mut peer_map = peers.lock().unwrap();
|
||||
let is_new = !peer_map.contains_key(&payload.author);
|
||||
|
||||
Reference in New Issue
Block a user