T02 · Agent Memory Poisoning
Error
- Location
- SKILL.md:390
- Finding
- Untrusted Session Content Can Be Promoted into Persistent Agent Instructions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:390-448` **Additional Locations**: `SKILL.md:48-55`, `hooks/openclaw/handler.js:11-25`, `references/openclaw-integration.md:122-143` **Vulnerability Type**: Persistent agent memory poisoning **Risk Level**: High ### Vulnerable Instructions `SKILL.md:390-405` treats user statements and other session-derived content as material to log automatically: ```markdown ## Detection Triggers Automatically log when you notice: **Corrections** (→ learning with `correction` category): - "No, that's not right..." - "Actually, it should be..." - "You're wrong about..." - "That's outdated..." **Feature Requests** (→ feature request): - "Can you also..." - "I wish you could..." - "Is there a way to..." - "Why can't you..." ``` `SKILL.md:440-448` then encourages aggressive promotion into persistent agent instruction files: ```markdown ## Best Practices 1. **Log immediately** - context is freshest right after the issue 2. **Be specific** - future agents need to understand quickly 3. **Include reproduction steps** - especially for errors 4. **Link related files** - makes fixes easier 5. **Suggest concrete fixes** - not just "investigate" 6. **Use consistent categories** - enables filtering 7. **Promote aggressively** - if in doubt, add to CLAUDE.md or .github/copilot-instructions.md 8. **Review regularly** - stale learnings lose value ``` The OpenClaw hook reinforces promotion into files loaded as agent context. From `hooks/openclaw/handler.js:11-25`: ```javascript After completing tasks, evaluate if any learnings should be captured: **Log when:** - User corrects you → \`.learnings/LEARNINGS.md\` - Command/operation fails → \`.learnings/ERRORS.md\` - User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\` - You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\` - You find a better approach → \`.learnings/LEARNINGS.md\` **Promote when pattern is proven:** - Behavioral patterns → \`S ...[truncated 4471 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Treat all learning sources as untrusted** - Explicitly classify user messages, tool output, API responses, web content, repository text, and cross-session messages as untrusted data. - State that instructions contained in those sources must never be promoted merely because they are phrased as corrections or best practices. 2. **Replace automatic or aggressive promotion with an approval gate** - Remove “Automatically log” and “Promote aggressively.” - Stage proposed entries in a non-injected quarantine file. - Require explicit human approval of a rendered diff before modifying `CLAUDE.md`, `AGENTS.md`, `SOUL.md`, `TOOLS.md`, or Copilot instruction files. - Display the source, destination, exact text, and security implications during approval. 3. **Separate archival data from executable prompt instructions** - Store raw observations in a data-only format that is not loaded as agent instructions. - Promote only concise, declarative facts through a strict schema. - Reject content that asks the agent to run commands, access secrets, contact external systems, disable safeguards, override higher-priority instructions, or modify trust controls. 4. **Add provenance and verification metadata** - Record source type, session identifier, author, timestamp, supporting evidence, reviewer, and approval status. - Require independent verification against trusted project documentation or tested behavior. - Do not treat repetition or recurrence alone as evidence of trustworthiness. 5. **Implement content security checks** - Detect imperative prompt-injection language and encoded or obfuscated instructions. - Redact credentials, tokens, private keys, personal information, environment values, and sensitive command output. - Reject entries containing external upload instructions or commands unless separately reviewed. 6. **Apply least privilege** - Prevent routine agents from writing directly t ...[truncated 1033 chars]
