T02 · Agent Memory Poisoning
- Location
scripts/focus.mjs:27- Finding
Persistent Agent Memory Poisoning Through Unsanitized Focus-State Fields
- Content
View full analysis
Vulnerability Details
File Location:
scripts/focus.mjs:27-44, 107-110, 124, 135, 165; related trust instructions inSKILL.md:24-26, 61-66
Vulnerability Type: Persistent agent memory poisoning through unsanitized Markdown content
Risk Level: MediumVulnerable 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
View remediation
Remediation Suggestions
- Treat all focus points, TODO text, context, and archive outcomes as untrusted data.
- Reject or normalize control characters and embedded carriage returns or newlines for fields intended to occupy one line.
- Escape Markdown metacharacters before rendering values, or store state in a strictly validated JSON document and render Markdown only for display.
- Define a schema with field types, maximum lengths, and allowed character policies; reject values that do not conform.
- Clearly delimit user-controlled values and add explicit instructions that agents must never interpret stored task content as operational or safety instructions.
- Keep data and instructions in separate channels where supported. Agents should treat loaded focus-state values as quoted records rather than authoritative directives.
- Apply the same validation to archive outcomes and any context imported from existing files.
- Add regression tests using inputs containing newlines, headings, section delimiters, instruction-like phrases, and oversized content to verify that they cannot alter document structure.
