T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/model_router.py:293
- Finding
- Full User Queries Are Silently Persisted in Plaintext<![CDATA[ ## Vulnerability Details **File Location**: `scripts/model_router.py`, lines 293 and 384-398 **Vulnerability Type**: Plaintext storage of potentially sensitive prompt data **Risk Level**: Medium ### Vulnerable Code ```python self._log_query(query, best_tier) ``` ```python def _log_query(self, query: str, tier: str) -> None: """Append the query + tier to the history file for offline analysis.""" try: history: list = [] if os.path.exists(self.history_file): with open(self.history_file, "r", encoding="utf-8") as f: raw = f.read().strip() if raw: history = json.loads(raw) history.append({"query": query, "tier": tier}) if len(history) > 1000: history = history[-1000:] with open(self.history_file, "w", encoding="utf-8") as f: json.dump(history, f, ensure_ascii=False, indent=2) except Exception: pass ``` ### Technical Analysis Every call to `ModelRouter.route()` invokes `_log_query()`, which stores the complete user query and its assigned tier in `query_history.json` by default. Logging is not disabled by default and does not require user consent. The history file can retain up to 1,000 complete prompts. No secret filtering, data minimization, encryption, explicit file permissions, or secure application-data location is used. Because the default path is relative, the file is created in the process working directory and may be exposed through source-control commits, shared workspaces, backups, build artifacts, or other local processes. Prompts commonly contain proprietary source code, credentials, personal information, internal architecture details, or confidential business data. Silently retaining this content violates data-minimization and secure-storage principles. The broad exception handler also conceals logging and permission failures, making the behavior difficult to monitor or audit. ### Attack Pa ...[truncated 1278 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable query-content logging by default and require explicit user opt-in. 2. Store only necessary derived metadata, such as an anonymous identifier, routing tier, and aggregate statistics. 3. Never retain raw prompts unless the user explicitly enables diagnostic logging. 4. Apply secret and personal-data redaction before writing any diagnostic records. 5. Store logs in a dedicated private application-data directory rather than the current working directory. 6. Create the history file with owner-only permissions, such as mode `0600` on POSIX systems. 7. Provide configurable retention limits and automatic expiration. 8. Document the logging behavior, file location, retained fields, and deletion procedure. 9. Replace the silent exception handler with controlled diagnostic reporting that does not expose prompt content. 10. Consider an explicit constructor option such as: ```python def __init__(self, ..., enable_history: bool = False): self.enable_history = enable_history ``` Then conditionally invoke logging: ```python if self.enable_history: self._log_query(query, best_tier) ``` ]]>
