T02 · Agent Memory Poisoning
- Location
distill_memory.py:17- Finding
Untrusted Conversation Content Can Poison Persistent Agent Memory
- Content
View full analysis
Vulnerability Details
File Location:
distill_memory.py:17-23, 58-74;memory_agent.py:122-180;SKILL.md:187-193, 343-352
Vulnerability Type: Untrusted content promoted to authoritative persistent memory
Risk Level: HighVulnerable Code
python FACT_PATTERNS = [ # (type, confidence, pattern, content_group) ("decision", "high", r"(?i)(decided to|we will always|agreed to|let's go with|finalize on)\s+([^.\n]+)", 2), ("decision", "high", r"(?i)(the final approach is|we are going with|confirmed:\s*)([^.\n]+)", 2), ("preference", "medium", r"(?i)(prefer|don't like|avoids?|wants? to use|hate)\s+([^.\n]+)", 0), ("constraint", "high", r"(?i)(must be|must not|requires?|cannot|do not use|only use|never use)\s+([^.\n]+)",0), ("next_action", "low", r"(?i)(todo|to-do|next step|next up|we need to|action item)\s*:?\s*([^.\n]+)", 2), ]python for turn_index, msg in enumerate(messages): role = msg.get("role", "unknown") content = msg.get("content", "") if not isinstance(content, str): continue for fact_type, confidence, pattern, content_group in FACT_PATTERNS: for m in re.finditer(pattern, content): extracted = m.group(content_group).strip() if content_group > 0 else m.group(0).strip() if len(extracted.split()) < 2: continue facts.append({ "id": str(uuid.uuid4())[:8], "type": fact_type, "content": extracted, "confidence": confidence, "source_turn": turn_index + 1, "source_role": role, })python if trigger_report["should_distill"]: if not args.history: result["distillation"] = { "success": False, "error": "Distillation triggered but --history path not provided. Cannot distill.", } else: result[" ...[truncated 2833 chars]- Remediation
View remediation
Remediation Suggestions
- Apply a strict role-based trust policy. Do not promote user, tool, retrieved-document, or unknown-role content to authoritative decisions or constraints.
- Store user-derived statements as untrusted claims rather than high-confidence facts.
- Require explicit user confirmation before persisting instruction-like decisions, constraints, credentials, destinations, or security settings.
- Preserve immutable provenance, including role, turn, session, timestamp, and a hash or reference to the original message.
- Add filters for imperative and policy-like content, especially phrases matching the existing decision and constraint patterns.
- Separate factual memory from behavioral instructions; persistent behavioral rules should require a dedicated authenticated workflow.
- Do not flush the original conversation until the extracted facts have been reviewed and accepted.
- Ensure retrieval consumers enforce confidence and role policies rather than trusting every stored fact.
- Disable automatic MCP persistence by default and require a confirmation boundary before invoking
memory_write.
