Skip to content

memory: peer_scoped_key is non-injective, causes cross-peer key collisions #5119

Description

@houko

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-522peer_scoped_key construction.
  • crates/librefang-kernel/src/kernel/handles/memory_access.rs:101-104memory_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

  1. Percent-encode : (and any reserved delimiter) in pid and key at write time; decode on read.
  2. Or store peer/key as separate columns (agent_id, peer_id, key) instead of synthesizing a composite primary key.
  3. Reject : in peer_id and key at the memory_store/memory_list boundary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/memorySQLite memory substratearea/securitySecurity systems and auditingbugSomething isn't workinghas-prA pull request has been linked to this issueseverity/criticalRemote-exploitable, data loss, or production-blocking

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions