T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/session-to-memory.py:23
- Finding
- Unredacted Session Content Is Persisted in Searchable Long-Term Memory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/session-to-memory.py:23-25, 76-104, 172-174, 222-224` **Vulnerability Type**: Plaintext persistence and indexing of potentially sensitive conversation data **Risk Level**: High ### Complete Code Snippet ```python SESSIONS_DIR = os.path.expanduser("~/.openclaw/agents/main/sessions") MEMORY_DIR = os.path.expanduser("~/.openclaw/workspace/memory/sessions") STATE_FILE = os.path.join(MEMORY_DIR, ".state.json") ``` ```python elif etype == "message": msg = entry.get("message", {}) role = msg.get("role", "unknown") content = extract_text_content(msg.get("content", "")) timestamp = entry.get("timestamp", "") # Skip empty messages, pure thinking, and tool-only messages if not content.strip() or content.strip() in ["", "\n\n"]: continue # Skip system messages (usually injected context) if role == "system": continue messages.append({ "role": role, "content": content.strip(), "timestamp": timestamp, }) ``` ```python if role == "user": # Try to extract just the human text (after timestamps) lines.append(f"**Dirk:** {content}") elif role == "assistant": # Truncate very long assistant responses (tool outputs, code, etc.) if len(content) > 2000: content = content[:2000] + "\n\n[...truncated...]" lines.append(f"**Faya:** {content}") else: lines.append(f"**{role}:** {content}") ``` ```python with open(out_path, "w") as f: f.write(result["markdown"]) ``` ### Technical Analysis The converter reads every qualifying JSONL session from the hardcoded OpenClaw session directory and copies message content into Markdown under `memory/sessions`. User messages are stored without redaction or a length limit. Assistant messages receive only a length limit and are not checked for secrets or personal information. The Skill documentation states that these Markdown files are automatically vectorized ...[truncated 2282 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require explicit operator consent before converting historical sessions, and support per-session or per-user allowlists. 2. Add configurable exclusions for sensitive sessions, roles, message classes, paths, and content types. 3. Apply redaction before writing output. Detect common API-token formats, authorization headers, passwords, private keys, cookies, connection strings, and other configured secret patterns. 4. Consider replacing detected values with stable placeholders so surrounding context remains searchable without retaining the secret. 5. Treat tool-derived and externally supplied content as sensitive by default, even when it appears inside a user or assistant message. 6. Create output files with restrictive permissions, such as mode `0600`, and ensure the containing directories are not accessible to unrelated users. 7. Add configurable retention periods and a deletion command that removes both source-derived Markdown and associated vector-index entries. 8. Document that generated transcripts contain sensitive data and must not be committed to source control, synchronized to public storage, or shared without review. 9. Provide a preview or dry-run mode that reports what will be retained and redacted before conversion. 10. Test redaction against representative credentials and verify that secrets cannot be recovered through memory search after source and generated files are deleted. ]]>
