T09 · Insecure Skill Coding Practices
- Location
src/optimizer.py:350- Finding
Plaintext Persistence of Potentially Sensitive Session Content
- Content
View full analysis
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: MediumVulnerable 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
View remediation
Remediation Suggestions
- Create the storage directory with mode
0700and each snapshot with mode0600, without relying on the process umask. Use an atomic owner-only file creation mechanism and reject symlink targets. - 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.
- Require an explicit session identifier for compression, or request confirmation before selecting the main or latest session automatically.
- Add a metadata-only or
--no-contentmode that stores token counts and tool-call statistics without retaining message text. - Clearly warn that compression snapshots can contain confidential conversation content and display the exact output path before or immediately after creation.
- Introduce a retention policy and a secure deletion command for old snapshots.
- Avoid placing sensitive snapshots in directories subject to automatic synchronization, indexing, or broad Agent access unless the user explicitly opts in.
- Consider encrypting snapshots at rest where plaintext retention is unavoidable.
- Add tests that verify restrictive permissions, secret redaction, explicit session selection, and safe handling of existing files and symlinks.
- Create the storage directory with mode
