T09 · Insecure Skill Coding Practices
- Location
tool.py:22- Finding
Plaintext Conversation Storage and Cross-Agent Data Mixing
- Content
View full analysis
Vulnerability Details
File Location:
tool.py:22-52andtool.py:58-92
Vulnerability Type: Plaintext storage of potentially sensitive data with insufficient agent-level isolation
Risk Level: MediumVulnerable Code
python class MemoryReflector: def __init__(self, memory_dir: str = ".agent_memory", window_size: int = 50): self.memory_dir = memory_dir self.window_size = window_size self.memory_log = os.path.join(memory_dir, "memory.jsonl") self.reflection_log = os.path.join(memory_dir, "reflections.jsonl") os.makedirs(memory_dir, exist_ok=True) def log_interaction(self, agent_id: str, prompt: str, response: str, metadata: Dict = None): """Log an agent's input/output for future reflection.""" entry = { "timestamp": datetime.utcnow().isoformat(), "agent_id": agent_id, "prompt": prompt, "response": response, "metadata": metadata or {}, "entry_hash": self._hash_entry(prompt, response) } with open(self.memory_log, "a") as f: f.write(json.dumps(entry) + "\n") def _load_recent_memories(self) -> List[Dict]: """Load the most recent interactions from memory.""" if not os.path.exists(self.memory_log): return [] with open(self.memory_log, "r") as f: lines = f.readlines() entries = [json.loads(line) for line in lines] return sorted(entries, key=lambda x: x["timestamp"], reverse=True)[:self.window_size]Reflection reports can propagate prompt content into a second plaintext file:
python if h in seen_hashes: patterns["repeated_queries"].append(mem["prompt"][:120]) seen_hashes.add(h) if any(phrase in mem["response"].lower() for phrase in ["i don't know", "unsure", "might be", "could be"]): patterns["high_uncertainty_ ...[truncated 3215 chars]- Remediation
View remediation
Remediation Suggestions
- Create the memory directory with an explicitly restrictive mode such as
0700, and verify or correct the mode when the directory already exists. - Create memory and reflection files with mode
0600by usingos.open()with explicit flags and permissions rather than relying solely on the process umask. - Separate storage by agent identifier. Validate and normalize the identifier before using it in a path to prevent path traversal.
- Pass the requested agent identifier into
_load_recent_memories()and filter every loaded record so reflection only processes records belonging to that agent. - Avoid storing complete prompts and responses by default. Support configurable field allowlists, secret redaction, truncation, or opt-in content retention.
- Do not copy complete prompts into reflection reports. Store aggregate counts or irreversible references unless raw content is explicitly required.
- Define configurable retention limits and provide secure deletion or purge functionality.
- Where sensitive records must be retained, encrypt them at rest with keys managed separately from the data files.
- Document that the memory directory contains potentially sensitive conversation data and must not be placed in shared or source-controlled locations.
- Add tests confirming restrictive permissions, per-agent isolation, redaction behavior, and the absence of one agent's records from another agent's reflection report.
- Create the memory directory with an explicitly restrictive mode such as
