T02 · Agent Memory Poisoning
- Location
listener.py:273- Finding
Peer-Controlled Content Is Persisted and Injected into Agent Sessions Without a Safe Trust Boundary
- Content
View full analysis
str: """Strip Unicode direction-override characters. SECURITY T1.""" return "".join(ch for ch in text if ord(ch) not in _DIRECTION_OVERRIDES) def strip_control_characters(text: str) -> str: """Strip null bytes and non-printable control characters.""" return "".join( ch for ch in text if ch == "\n" or ch == "\t" or (not unicodedata.category(ch).startswith("C")) ) def sanitize_string(text: str) -> str: """Full sanitization pipeline for untrusted peer strings. SECURITY T1.""" if not isinstance(text, str): raise ValueError("Expected string input") result = strip_direction_overrides(text) result = strip_control_characters(result) return result ``` The listener computes whether the peer is trusted, but the inbound `HANDOFF` branch persists peer-controlled fields without enforcing that result: ```python # Peer trust check — SECURITY T4 trusted = is_peer_trusted(workspace_root, peer_pubkey_hex) # Receive the incoming message — could be PROPOSE (negotiation) or HANDOFF (context passing) try: incoming_msg = await recv_noise_message(noise_conn, ws, timeout=60.0) except (asyncio.TimeoutError, ValueError, websockets.exceptions.ConnectionClosed) as e: LOG.info("No message received from %s: %s", peer_ip, e) return msg_type_recv = incoming_msg.get("msg_type") # ── HANDOFF: peer is passing completed work + context ────────────────────── if msg_type_recv == MsgType.HAND ...[truncated 5724 chars]- Remediation
View remediation
