T02 · Agent Memory Poisoning
Error
- Location
- scripts/auto_retrieve.py:208
- Finding
- Persistent Prompt Injection Through Untrusted Memory Retrieval<![CDATA[ ## Vulnerability Details **File Location**: `scripts/indexer.py:25-28`, `scripts/auto_retrieve.py:208-250`, `scripts/unified_setup.sh:78-87`, `SKILL.md:80-100` **Vulnerability Type**: Persistent memory poisoning and prompt injection **Risk Level**: High ### Vulnerable Code `scripts/indexer.py:25-28`: ```python with open(file_path, 'r', encoding='utf-8') as f: content = f.read() ``` `scripts/auto_retrieve.py:208-250`: ```python def auto_retrieve(query_text, n_results=5): """ Main entry point: auto-retrieve memory context for a query. Returns formatted markdown ready for system prompt injection. """ vector = query_chromadb(query_text, n_results) graph = query_graph(query_text) sync = get_sync_status() lines = [] lines.append("## 🧠 Auto-Retrieved Memory Context") lines.append(f"**Query:** {query_text}") lines.append(f"**Sync Status:** {sync['status']} | MEMORY.md hash: {sync.get('memoryMdHash', '?')} | Last sync: {sync.get('lastSync', 'never')}") lines.append("") # Vector results lines.append(f"### Vector Search (ChromaDB — {vector.get('count', '?')} chunks indexed)") if vector.get("error"): lines.append(f"⚠️ Error: {vector['error']}") elif vector["results"]: for r in vector["results"]: lines.append(f"- **[{r['section']}]** {r['relevance']}") lines.append(f" {r['snippet']}") else: lines.append("No relevant results found.") lines.append("") # Graph results lines.append(f"### Knowledge Graph (NetworkX — {graph.get('nodes', '?')} nodes, {graph.get('edges', '?')} edges)") if graph.get("error"): lines.append(f"⚠️ Error: {graph['error']}") elif graph["related"]: for r in graph["related"]: neighbors_str = ", ".join(r["neighbors"][:5]) if r["neighbors"] else "no direct neighbors" lines.append(f"- **{r['node']}** → {neighbors_str}") else: lines.append("No matching g ...[truncated 3572 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat all retrieved memory as untrusted data rather than executable instructions. 2. Place retrieved content in a strongly delimited, data-only context and explicitly tell the agent never to follow instructions found inside that content. 3. Record provenance, author, creation time, trust level, and integrity information for every indexed chunk. 4. Exclude session data and directive files from default indexing. Require explicit approval for each additional source. 5. Restrict write access to indexed directories and separate user-authored notes from tool-generated or externally imported content. 6. Detect and quarantine instruction-like content before indexing. Suspicious entries should require human review before becoming retrievable. 7. Do not automatically promote retrieved text into `SOUL.md`, `AGENTS.md`, or other behavioral configuration. 8. Apply output encoding and structured retrieval formats so memory content cannot masquerade as system or developer instructions. 9. Require explicit user confirmation before acting on retrieved content that requests tool execution, data disclosure, configuration changes, or external communication. 10. Provide deletion, revocation, and re-indexing controls for poisoned entries. ]]>
