T09 · Insecure Skill Coding Practices
Warning
- Location
- src/optimizer.py:350
- Finding
- Plaintext Persistence of Potentially Sensitive Session Content## Vulnerability Details **File Location**: `src/optimizer.py:350-397` **Related Sensitive-Data Extraction**: `src/compression.py:27-59` **Vulnerability Type**: Plaintext storage of sensitive conversation content with permissions inherited from the process umask **Risk Level**: Medium ### Vulnerable Code ```python sid = str(target.get("sessionId") or "") events = self.transcript_events(sid) summary = summarize_transcript_events(events, keep_recent=keep_recent) self.compressed_dir.mkdir(parents=True, exist_ok=True) out_path = self.compressed_dir / f"{sid}-compressed.md" lines = [ f"# Compressed Context: {target.get('key')}", "", f"- Session ID: `{sid}`", f"- Model: `{target.get('model')}`", f"- Tokens: `{total}/{context}` ({utilization:.0%})", "", "## Original Task", summary.get("firstUser", "(no user prompt found)"), "", "## Tool Call Summary", ] tool_calls = summary.get("toolCalls", {}) if tool_calls: for name, count in sorted(tool_calls.items(), key=lambda kv: kv[1], reverse=True): lines.append(f"- `{name}`: {count}") else: lines.append("- No tool calls detected.") lines.extend(["", "## Recent Conversation", ""]) recent = summary.get("recent", []) if recent: for item in recent: role = item.get("role", "unknown") text = item.get("text", "") lines.append(f"- **{role}**: {text}") else: lines.append("- No recent text messages detected.") lines.extend( [ "", "## Compression Guidance", "- Keep this file in context, not the full raw transcript.", "- Re-run `token-optimize --compress` after major tool-heavy steps.", "- If utilization remains high, start a fresh session and continue from this summary.", ] ) out_path.write_text("\n".join(lines).strip() + "\n", encoding="utf-8") ``` The content placed into that file is extracted as follows: ```python def summarize_transcript_events(events: list[dict], keep_recent: int = 20) ...[truncated 4310 chars]
- Remediation
- ## Remediation Suggestions 1. Create the storage directory with mode `0700` and each snapshot with mode `0600`, without relying on the process umask. Use an atomic owner-only file creation mechanism and reject symlink targets. 2. Redact likely secrets before writing. Cover bearer tokens, API keys, authorization headers, passwords, private keys, connection strings, signed URLs, cookies, and configurable organization-specific patterns. 3. Require an explicit session identifier for compression, or request confirmation before selecting the main or latest session automatically. 4. Add a metadata-only or `--no-content` mode that stores token counts and tool-call statistics without retaining message text. 5. Clearly warn that compression snapshots can contain confidential conversation content and display the exact output path before or immediately after creation. 6. Introduce a retention policy and a secure deletion command for old snapshots. 7. Avoid placing sensitive snapshots in directories subject to automatic synchronization, indexing, or broad Agent access unless the user explicitly opts in. 8. Consider encrypting snapshots at rest where plaintext retention is unavoidable. 9. Add tests that verify restrictive permissions, secret redaction, explicit session selection, and safe handling of existing files and symlinks.
