T02 · Agent Memory Poisoning
Error
- Location
- SKILL.md:71
- Finding
- Untrusted Content Can Be Persisted and Promoted into Long-Term Agent Behavior<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:71-88` **Supporting Locations**: `hooks/openclaw/handler.js:8-25, 46-52`; `hooks/openclaw/handler.ts:9-26, 53-59` **Vulnerability Type**: Persistent agent memory poisoning **Risk Level**: High ### Vulnerable Code `SKILL.md:71-88`: ```markdown ## Automated triggers These fire without user prompting: 1. **Post-task scan**: After multi-step tasks, check for retried commands, error→workaround sequences, or avoidable file reads. If found, evaluate against write gate and log if it passes. 2. **Session-start sweep**: On `.learnings/LEARNINGS.md` read, flag entries >90 days old for retention scoring. 3. **Promotion detector**: After logging, scan for entries with the same `[Category]` tag appearing 3+ times. If found, auto-suggest a one-liner promotion to: - behavior/style → `SOUL.md` - workflow/process → `AGENTS.md` - tool/env gotcha → `TOOLS.md` 4. **Cross-session pattern detection**: When `memory_search` returns a daily note describing a workaround, check if `.learnings/` already has it. If not and it passes the write gate, log it. ``` `hooks/openclaw/handler.js:8-25, 46-52`: ```javascript const REMINDER_CONTENT = ` ## Self-Improvement Reminder 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 → \`SOUL.md\` - Workflow improvements → \`AGENTS.md\` - Tool gotchas → \`TOOLS.md\` Keep entries simple: date, title, what happened, what to do differently. `.trim(); // Inject the reminder as a virtual bootstrap file // Check that bootstrapFiles is an array before pushing if (Array.isArray(event.contex ...[truncated 3206 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Require explicit approval before persistence** - Present the proposed learning verbatim to a trusted user. - Do not write it until the user explicitly approves the exact text and destination. - Require a separate confirmation before promotion into `SOUL.md`, `AGENTS.md`, or `TOOLS.md`. 2. **Store structured facts instead of free-form instructions** - Use fields such as source, timestamp, project scope, confidence, expiration, and evidence. - Separate descriptive observations from recommended actions. - Prevent learning entries from containing role changes, policy overrides, or imperatives directed at the agent. 3. **Add instruction-safety validation** - Reject entries that request credential access, secret disclosure, external communication, command execution, permission changes, disabling safeguards, or modification of agent policy. - Treat user messages and `memory_search` results as untrusted data regardless of recurrence. 4. **Track provenance and trust boundaries** - Record the originating session, user identity or trust level, and source message. - Do not allow low-trust or unknown sources to influence global behavior files. - Scope project-specific observations to the relevant project rather than global memory. 5. **Remove recurrence as proof of trust** - Repetition should not make a claim eligible for behavioral promotion. - Require independent verification against trusted documentation, configuration, or code. - Detect near-duplicate submissions intended to manipulate the recurrence threshold. 6. **Constrain promotion** - Generate review-only proposals in a quarantine file rather than modifying behavior files. - Validate promotions against an allowlist of harmless categories. - Preserve an audit trail and provide a straightforward rollback mechanism. 7. **Reduce bootstrap reinforcement** - Update the injected reminder to state that all conversational and m ...[truncated 137 chars]
