Problem
peer_scoped_key(key, peer_id) = format!("peer:{pid}:{key}") is not injective: the colon delimiter is not escaped in either pid or key, and memory_list recovers peer keys by strip_prefix("peer:{pid}:"). A peer id containing : collides with a different (peer_id, key) pair, leaking the latter's keys into the former's listing.
Evidence
crates/librefang-kernel/src/kernel/manifest_helpers.rs:517-522 — peer_scoped_key construction.
crates/librefang-kernel/src/kernel/handles/memory_access.rs:101-104 — memory_list filter:
let prefix = format!("peer:{pid}:");
all_keys.into_iter()
.filter_map(|k| k.strip_prefix(&prefix).map(|s| s.to_string()))
The test at kernel/tests.rs:1746-1748 pins this fragile format.
Concrete collision: peer "u" writing key "456:prefs.color" and peer "u:456" writing key "prefs.color" both serialize to peer:u:456:prefs.color. memory_list(Some("u")) returns the stripped tail 456:prefs.color for both rows.
Impact
Cross-peer key leakage in memory_list, ambiguous identity for any peer_id that contains : (chat IDs from some channels do — e.g. user:42, Slack T1:U2). The two writers' values overwrite each other on the same key, and the operator has no warning that one peer is reading another peer's data.
Suggested fix
- Percent-encode
: (and any reserved delimiter) in pid and key at write time; decode on read.
- Or store peer/key as separate columns (
agent_id, peer_id, key) instead of synthesizing a composite primary key.
- Reject
: in peer_id and key at the memory_store/memory_list boundary.
Problem
peer_scoped_key(key, peer_id) = format!("peer:{pid}:{key}")is not injective: the colon delimiter is not escaped in eitherpidorkey, andmemory_listrecovers peer keys bystrip_prefix("peer:{pid}:"). A peer id containing:collides with a different (peer_id, key) pair, leaking the latter's keys into the former's listing.Evidence
crates/librefang-kernel/src/kernel/manifest_helpers.rs:517-522—peer_scoped_keyconstruction.crates/librefang-kernel/src/kernel/handles/memory_access.rs:101-104—memory_listfilter:The test at
kernel/tests.rs:1746-1748pins this fragile format.Concrete collision: peer
"u"writing key"456:prefs.color"and peer"u:456"writing key"prefs.color"both serialize topeer:u:456:prefs.color.memory_list(Some("u"))returns the stripped tail456:prefs.colorfor both rows.Impact
Cross-peer key leakage in
memory_list, ambiguous identity for any peer_id that contains:(chat IDs from some channels do — e.g.user:42, SlackT1:U2). The two writers' values overwrite each other on the same key, and the operator has no warning that one peer is reading another peer's data.Suggested fix
:(and any reserved delimiter) inpidandkeyat write time; decode on read.agent_id,peer_id,key) instead of synthesizing a composite primary key.:in peer_id and key at thememory_store/memory_listboundary.