T02 · Agent Memory Poisoning
- Location
sogni-agent.mjs:7421- Finding
Persistent Prompt Injection Through Memory and Personality State
- Content
View full analysis
0) { const memoryContext = memories.map((m) => `${m.key}: ${m.value}`).join('; '); suffix += `\nUser preferences (apply unless the latest user request overrides them): ${memoryContext}`; } } catch { // best-effort } // Personality context — verbatim user instruction wrapped in the same // framing sogni-chat uses so the LLM treats it as an override. try { const personality = loadPersonality(); if (personality) { suffix += `\nUSER PERSONALITY PREFERENCE: The user has customized your personality as follows: "${personality}". Adopt this personality while following all other instructions above.`; } } catch { // best-effort } ``` The affected values are persisted without content validation: ```js function memorySet(key, value, category = 'preference', source = 'user') { const memories = loadMemories(); const existing = memories.findIndex(m => m.key === key); const entry = { key, value, category, source, updatedAt: Date.now() }; if (existing >= 0) { memories[existing] = { ...memories[existing], ...entry }; } else { memories.push({ id: randomBytes(8).toString('hex'), ...entry, createdAt: Date.now() }); } saveMemories(memories); return existing >= 0 ? 'updated' : 'created'; } function savePersonality(text) { const dir = dirname(PERSONALITY_PATH); if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); writeFileSync(PERSONALITY_PATH, text); } ``` ### Technical Analysis Memory keys, memory values, and personality text are interpolated verbatim into the hosted LLM's system message. The implementation does not impose size limits, normalize line breaks, esc ...[truncated 2105 chars]- Remediation
View remediation
