T02 · Agent Memory Poisoning
Error
- Location
- scripts/log-error.sh:29
- Finding
- Untrusted Transcript Content Can Poison Persistent Agent Memory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/log-error.sh:29-42`, `scripts/log-error.sh:77-87`, `scripts/sync-state.sh:45-71`, `SKILL.md:227-239` **Vulnerability Type**: Persistent storage and reinjection of untrusted behavioral instructions **Risk Level**: High ### Complete Code Snippet ```bash # scripts/log-error.sh:29-42 PATTERN="$PATTERN" CONTEXT="$CONTEXT" MITIGATION="$MITIGATION" python3 << 'PYTHON' import json from datetime import datetime, timezone from pathlib import Path import os workspace = os.environ.get('WORKSPACE', os.path.expanduser('~/.openclaw/workspace')) state_file = Path(workspace) / 'memory' / 'acc-state.json' pattern = os.environ.get('PATTERN', '') context = os.environ.get('CONTEXT', '') mitigation = os.environ.get('MITIGATION', '') ``` ```python # scripts/log-error.sh:77-87 active[pattern] = { 'count': old_data_copy.get('count', 0) + 1, 'severity': 'critical', # Regressions are always critical 'firstSeen': old_data_copy.get('firstSeen', now), 'lastSeen': now, 'context': context or old_data_copy.get('context', ''), 'mitigation': mitigation or old_mitigation, 'regression': True, 'previouslyResolvedOn': old_data_copy.get('resolvedOn'), 'failedLesson': old_lesson if isinstance(old_lesson, dict) else {'mitigation': old_mitigation}, } ``` ```python # scripts/sync-state.sh:45-71 if critical: lines.append("## 🔴 REPEATED ERRORS — Act on these!") lines.append("") lines.append("| Pattern | Count | Last | Mitigation |") lines.append("|---------|-------|------|------------|") for name, data in sorted(critical.items(), key=lambda x: -x[1].get('count', 0)): count = data.get('count', 0) last = data.get('lastSeen', 'unknown')[:10] mitigation = data.get('mitigation', 'be careful') regression = " ⚠️ REGRESSION" if data.get('regression') else "" lines.append(f"| {name}{regression} | {count}x | {last} | {mitigation} |") lines.append("" ...[truncated 3102 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat every transcript-derived field as untrusted data rather than executable guidance. 2. Replace free-form mitigations with a fixed, allowlisted schema of narrowly defined actions. 3. Require explicit user or administrator approval before persisting a generated mitigation. 4. Add strict length, character, and content validation to pattern names, contexts, and mitigations. 5. Reject imperative instructions, references to system prompts, tool commands, credential access, safety overrides, and external URLs. 6. Escape Markdown control characters before rendering stored values. 7. Place transcript-derived content inside clearly delimited quoted blocks labeled as untrusted historical data. 8. Add an immutable preamble to generated state stating that its contents cannot override system, developer, user, or safety instructions. 9. Separate observational memory from behavioral policy; do not automatically inject free-form observations into future prompts. 10. Record provenance for every entry, including source session, generating model, approval status, and creation time. 11. Provide review, expiration, and deletion controls for persisted entries. ]]>
