T02 · Agent Memory Poisoning
- Location
scripts/session-to-memory.js:72- Finding
Untrusted Session Content Is Persisted Without Neutralizing Embedded Instructions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/session-to-memory.js, lines 72–91 and 127–163
Vulnerability Type: Persistent memory poisoning through untrusted transcript ingestion
Risk Level: MediumVulnerable Code
js function extractMessages(lines, maxMessages) { const messages = []; for (const obj of lines) { if (obj.type !== 'message' || !obj.message) continue; const role = obj.message.role; if (role !== 'user' && role !== 'assistant') continue; const parts = obj.message.content || []; for (const p of parts) { if (p.type === 'text' && p.text && typeof p.text === 'string') { const text = p.text.trim(); if (text.length > 0) messages.push({ role, text, ts: obj.timestamp }); if (messages.length >= maxMessages) return messages; } } } return messages; } function buildSummaryMarkdown(sessionId, date, messages) { const lines = [ `### Session ${sessionId.slice(0, 8)}`, '', ]; for (const m of messages) { const label = m.role === 'user' ? '**User**' : '**Assistant**'; const preview = m.text.slice(0, 800) + (m.text.length > 800 ? '…' : ''); lines.push(`- ${label}: ${preview.replace(/\n/g, ' ')}`); } lines.push(''); return lines.join('\n'); }js let body = ''; for (const { sessionId, messages } of sessionsForDate) { body += buildSummaryMarkdown(sessionId, date, messages); } const newSection = `## Session summary\n\n${body}`; try { if (!fs.existsSync(memoryDir)) fs.mkdirSync(memoryDir, { recursive: true }); } catch (e) { console.error(JSON.stringify({ ok: false, error: `mkdir memory: ${e.message}` })); process.exit(1); } let finalContent; if (opts.append && fs.existsSync(memoryFile)) { const existing = fs.readFileSync(memoryFile, 'utf-8'); if (existing.match(/\n## Session summary\n/i)) { finalContent = existing.replace(/\n## Session summary\n[\s\S]*/i, '\n' + newSection); } else { finalContent = existing.trimEnd() + ' ...[truncated 2681 chars]- Remediation
View remediation
Remediation Suggestions
- Treat every imported transcript field as untrusted data and preserve that trust classification in structured metadata.
- Store transcript excerpts in a clearly delimited quotation or data block that downstream prompts explicitly prohibit from supplying instructions.
- Escape or neutralize Markdown constructs and control-like syntax before writing excerpts to memory.
- Prefer generating a constrained factual summary rather than copying raw messages. Validate the summary against a schema that excludes directives, tool requests, and behavioral rules.
- Add detection for instruction-hijacking patterns and either omit flagged content or require explicit user confirmation before persistence.
- Separate historical conversation archives from trusted agent memory. Retrieval logic should place archives in an untrusted context section.
- Ensure downstream memory consumers follow an enforced rule that retrieved session text is evidence only and cannot override system, developer, or current-user instructions.
- Record provenance, original role, session identifier, and creation time for each entry so retrieved material can be evaluated appropriately.
- Add security tests using messages such as “ignore previous instructions” and verify that persisted and retrieved content cannot alter agent behavior.
