T02 · Agent Memory Poisoning
Error
- Location
- hooks/handler.js:286
- Finding
- Persistent memory poisoning through verbatim message storage and context injection<![CDATA[ ## Vulnerability Details **File Location**: `hooks/handler.js:286-296`; `scripts/memory-extract.js:91-113`; `scripts/auto-memory-search.js:216-220` **Vulnerability Type**: Persistent prompt injection through agent memory **Risk Level**: High ### Vulnerable Code ```js // hooks/handler.js:286-296 console.log(`[MemorySearch] Detected message type: ${msgType}`); const searchResults = await searchMemory(userMessage); if (searchResults) { event.messages.push(`📚 Relevant memory:\n${searchResults}`); console.log('[MemorySearch] Memory injected'); } // Automatic memory extraction in the background console.log('[MemoryExtract] Triggering background memory extraction'); extractMemoryAsync(userMessage); ``` ```js // scripts/memory-extract.js:91-113 function writeMemory(type, title, content, tags = []) { ensureDirs(); if (isDuplicate(type, content)) { return { success: false, reason: 'duplicate' }; } const filename = generateFilename(type, title); const filepath = path.join(MEMORY_DIR, type, filename); const now = new Date().toISOString().split('T')[0]; const memoryContent = `--- type: ${type} created: ${now} tags: [${tags.join(', ')}] --- # ${title} ${content} `; fs.writeFileSync(filepath, memoryContent, 'utf8'); ``` ```js // scripts/auto-memory-search.js:216-220 if (allResults.length === 0) { console.log('📭 No related memory found'); } else { console.log('\n✅ Multi-dimensional memory search completed\n'); console.log(allResults.join('\n\n')); console.log('\n---\nThe memory above is for reference; cite it as appropriate'); } ``` ### Technical Analysis Every eligible user message is passed to `memory-extract.js`, which stores the message body verbatim in a persistent Markdown file. The retrieval code subsequently prints matching stored text without sanitization, and the message hook appends that output directly to `event.messages`. There is no separation between trusted instructions and untrusted recalled data. The im ...[truncated 1740 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not inject raw memory text into an instruction-bearing message list. 2. Store structured, minimal facts rather than complete messages. 3. Reject or quarantine content containing imperative instructions, role changes, safety overrides, tool-use directives, or prompt-injection indicators. 4. Preserve provenance, author, timestamp, and trust level for every memory item. 5. Present retrieved memory as explicitly quoted, untrusted data through a dedicated data channel. 6. Require explicit user approval before creating durable memories. 7. Apply retrieval allowlists and relevance thresholds rather than broad keyword matching. 8. Add tests demonstrating that stored instructions cannot alter later agent behavior. 9. Provide controls to inspect, edit, quarantine, and delete stored memories. ]]>
