T02 · Agent Memory Poisoning
- Location
todo_tracker.py:36- Finding
Attacker-Controlled Task Titles Are Persisted in Agent Memory
- Content
View full analysis
Vulnerability Details
File Location:
todo_tracker.py:16, 36-54, 80
Vulnerability Type: Persistent agent-memory poisoning
Risk Level: MediumVulnerable Code
python MEMORY_PATH = Path.home() / ".openclaw" / "workspace" / "MEMORY.md"python def append_to_memory(todo_list): """Write to MEMORY.md""" try: if not MEMORY_PATH.exists(): return entry = f""" ## Todo Task [{todo_list['id']}] - Creation time: {todo_list['createdAt']} - Task: {todo_list['title']} - Status: {len([i for i in todo_list['items'] if i['status'] == 'completed'])}/{len(todo_list['items'])} completed """ with open(MEMORY_PATH, 'a', encoding='utf-8') as f: f.write(entry) except Exception as e: print(f"Failed to write to MEMORY.md: {e}")python if save_todo_list(todo_list): append_to_memory(todo_list)Technical Analysis
The
generate_todo_listworkflow passes a user-supplied task description into the todo-list title and then callsappend_to_memory. That function interpolates the title directly into~/.openclaw/workspace/MEMORY.md, which may be loaded as persistent context by an AI agent in later sessions.The task title is truncated to 50 characters elsewhere in the code, but it is not escaped, validated, or explicitly marked as untrusted content before being written to the Markdown memory file. Newlines and Markdown instruction syntax are not removed. Consequently, a crafted task description can add instruction-like text to persistent agent state.
This write occurs immediately when a list is generated, rather than after verified completion. It also conflicts with the documented behavior in
SKILL.md, which states that completed tasks are recorded in~/self-improving/corrections.md; the implementation instead writes every generated task to the agent'sMEMORY.md.Exploitation requires the tar ...[truncated 1681 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove the automatic write to
MEMORY.mdunless persistent agent-memory integration is essential to the skill's declared purpose. - Store todo history in a dedicated structured data file that is not loaded as agent instructions, such as a JSON file under a skill-specific data directory.
- Require explicit user consent before modifying persistent agent memory, and clearly disclose the exact destination and content.
- If memory integration must remain, serialize the task as explicitly untrusted data and ensure the downstream agent treats the entire record as data rather than instructions.
- Reject or encode control characters, newlines, Markdown headings, and other instruction-formatting syntax in task titles before persistence.
- Use a strict allowlist for task-title characters and enforce a small length limit after normalization.
- Append records only after
verify_completionconfirms completion if archival after completion is the intended behavior. - Align the implementation, documentation, and declared permissions regarding whether data is written to
MEMORY.mdor a corrections archive. - Add tests using task descriptions containing newlines, Markdown directives, and prompt-injection language to verify that they cannot become executable agent instructions.
- Remove the automatic write to
