T02 · Agent Memory Poisoning
- Location
index.js:86- Finding
Persistent Agent Memory Poisoning Through Untrusted Conversation Content
- Content
View full analysis
m.content && m.content.trim().length > 0) .map(m => `**${m.role}**: ${m.content}`) .join('\n\n'); // Call LLM to extract key points const prompt = getExtractionPrompt(conversation); const result = await ctx.invokeLLM(prompt); // Parse result let extracted; try { // Try to extract JSON from response const jsonMatch = result.match(/```json\n([\s\S]*)\n```/) || result.match(/{[\s\S]*}/); const jsonStr = jsonMatch ? jsonMatch[1] || jsonMatch[0] : result; extracted = JSON.parse(jsonStr.trim()); } catch (err) { ctx.log.error('[memory-auto-manager] Failed to parse LLM response:', err); // Fallback: treat entire response as keyPoints extracted = { keyPoints: result.trim(), category: 'fact' }; } const { keyPoints, category = 'fact' } = extracted; // Check if worth retaining if (!keyPoints || typeof keyPoints !== 'string' || keyPoints.trim().length < 20) { ctx.log.info('[memory-auto-manager] Skipping: content too short or empty'); return; } // Write to MEMORY.md const memoryPath = path.join(ctx.workspace, 'MEMORY.md'); const date = new Date().toISOString().split('T')[0]; const timestamp = new Date().toISOString(); const content = ` --- ### ${timestamp} ### ${date} / ${category} ${keyPoints.trim()} --- `; await fs.promises.appendFile(memoryPath, content, 'utf8'); ctx.log.info(`[memory-auto-manager] ✉️ Wrote key points to MEMORY.md (timestamp: ${timestamp})`); // Update vector index ctx.log.info('[memory-auto-manager] 🔄 Updating vector memory index...'); await ctx.exec('openclaw memory index --force'); ``` ```js function getExtractionPrompt(conversation) ...[truncated 3038 chars]- Remediation
View remediation
