T02 · Agent Memory Poisoning
Error
- Location
- src/core/context-injector.js:47
- Finding
- Persistent Untrusted Memory Is Injected into the System Role<![CDATA[ ## Vulnerability Details **File Location**: `src/core/context-injector.js:47-52`; related processing and persistence occur at `src/core/gene-processor.js:49-55` and `src/storage/capsule-store.js:42-65` **Vulnerability Type**: Persistent prompt injection through agent memory **Risk Level**: High ### Evidence `src/core/gene-processor.js:49-55` accepts LLM-generated JSON without security-policy validation: ```js const response = await this.llmClient.ask(prompt); const cleanJson = response.replace(/```json|```/g, '').trim(); const distilled = JSON.parse(cleanJson); const searchKey = `${distilled.triggerPattern} ${distilled.rootCause}`; const embedding = await this.embed.vectorize(searchKey); ``` `src/storage/capsule-store.js:42-65` validates only the schema and then persistently stores the generated capsule: ```js save(capsule) { this.validator.assertValid(capsule); const embeddingString = JSON.stringify(capsule.triggerSignature.embedding); const tagsString = JSON.stringify(capsule.tags || []); const stmt = this.db.prepare(` INSERT OR REPLACE INTO engram_capsules (capsuleId, schemaVersion, category, trustScore, useCount, tags, vector, rawPayload) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `); stmt.run( capsule.capsuleId, capsule.schemaVersion, capsule.category, capsule.trustScore, capsule.useCount, tagsString, embeddingString, JSON.stringify(capsule) ); } ``` `src/core/context-injector.js:47-52` promotes the resulting advice to the trusted system role: ```js inject(history, advice) { if (!advice) return history; return [ ...history, { role: 'system', content: advice } ]; } ``` ### Technical Analysis Conversation-derived data is passed to an LLM and parsed as a structured capsule. The schema validator checks data types and required fields, but it does not determine whether fields such as `instruction`, `rationale`, or `antipatternWarning` contain prompt-control directive ...[truncated 2133 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Never promote retrieved or persisted capsule content to the `system` role. Insert it as explicitly untrusted reference material in a lower-privilege role. 2. Separate data from instructions using a fixed system prompt that states capsule text must not override policy, request tools, or alter current goals. 3. Apply deterministic content-policy validation before storage and again before retrieval. Reject prompt-control phrases, credential requests, destructive commands, security-control bypasses, and unauthorized network instructions. 4. Require explicit user confirmation before committing conversation-derived memories and before carrying out any command suggested by a capsule. 5. Store provenance metadata, including creator, source session, verification status, and content hash. 6. Keep draft capsules quarantined and excluded from retrieval until verification succeeds. 7. Replace LLM-only verification with enforceable allowlists and command-policy checks. LLM review may supplement but must not replace deterministic controls. 8. Add deletion, expiration, audit, and rollback mechanisms for poisoned capsules. 9. Constrain formatted fields by length and character policy, and render them as quoted data rather than authoritative instructions. ]]>
