T02 · Agent Memory Poisoning
Warning
- Location
- scripts/focus.mjs:27
- Finding
- Persistent Agent Memory Poisoning Through Unsanitized Focus-State Fields## Vulnerability Details **File Location**: `scripts/focus.mjs:27-44, 107-110, 124, 135, 165`; related trust instructions in `SKILL.md:24-26, 61-66` **Vulnerability Type**: Persistent agent memory poisoning through unsanitized Markdown content **Risk Level**: Medium ### Vulnerable Code ```js function generateFocus(focusPoint, todos = [], context = '', status = 'active') { // ... let output = `# FOCUS.md - 当前聚焦\n\n`; output += `🎯 **Focus Point**: ${focusPoint || '无'}\n\n`; output += `**Started:** ${new Date().toISOString().split('T')[0]}\n`; output += `**Status:** ${stateIcons[status] || '🟢'} ${status}\n\n`; if (todos.length > 0) { output += `📝 TODOs\n`; todos.forEach(todo => { const icon = todo.done ? '✅' : '☐'; output += `${icon} ${todo.content}\n`; }); output += `\n`; } output += `📖 Context\n`; output += context || '无\n'; output += `\n---\n*最后更新: ${now}*\n`; return output; } ``` ```js const entry = `\n## ${statusEmoji} ${data.focusPoint} — ${archiveType} ${completedDate}\n**Started:** ${data.started || completedDate}\n**Outcome:** ${outcome || '任务完成'}\n**Status:** ${allCompleted ? '全部完成' : '未完成'}\n`; ``` ```js case 'init': const focusPoint = args.slice(1).join(' ') || '新项目'; fs.writeFileSync(FOCUS_PATH, generateFocus(focusPoint, [], '', 'active')); console.log('✅ FOCUS.md created:', focusPoint); break; case 'add-todo': const data = parseFocus(); if (!data) { console.error('❌ No FOCUS.md found. Run "init" first.'); process.exit(1); } data.todos.push({ done: false, content: args.slice(1).join(' ') }); fs.writeFileSync(FOCUS_PATH, generateFocus(data.focusPoint, data.todos, data.context, data.status)); console.log('✅ Todo added'); break; ``` ```js case 'archive': archive(args.slice(1).join(' ')); break; ``` The related documentation establishes the generated file as trusted persistent agent context: ```markdown ## When to Read FOCUS.md - **Every session start** (be ...[truncated 2752 chars]
- Remediation
- ## Remediation Suggestions 1. Treat all focus points, TODO text, context, and archive outcomes as untrusted data. 2. Reject or normalize control characters and embedded carriage returns or newlines for fields intended to occupy one line. 3. Escape Markdown metacharacters before rendering values, or store state in a strictly validated JSON document and render Markdown only for display. 4. Define a schema with field types, maximum lengths, and allowed character policies; reject values that do not conform. 5. Clearly delimit user-controlled values and add explicit instructions that agents must never interpret stored task content as operational or safety instructions. 6. Keep data and instructions in separate channels where supported. Agents should treat loaded focus-state values as quoted records rather than authoritative directives. 7. Apply the same validation to archive outcomes and any context imported from existing files. 8. Add regression tests using inputs containing newlines, headings, section delimiters, instruction-like phrases, and oversized content to verify that they cannot alter document structure.
