T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/pattern_learner.py:58
- Finding
- Unredacted Collection and Persistent Storage of Potentially Sensitive Workspace Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pattern_learner.py`, lines 58–68, 77–86, 124–158, and 174–176 **Vulnerability Type**: Plaintext retention of potentially sensitive commands and error messages **Risk Level**: Medium ### Vulnerable Code ```python def learn_from_operations(self, days=7): """Learn from operation history.""" log("Learning from operations...") try: memory_dir = WORKSPACE / "memory" since = datetime.now() - timedelta(days=days) for file in memory_dir.rglob("*.md"): if not self._is_recent(file, since): continue with open(file) as f: content = f.read() # Find operation patterns self._extract_command_patterns(content) self._extract_workflow_patterns(content) self._extract_error_patterns(content) def learn_from_errors(self, days=7): """Learn from error logs.""" log("Learning from errors...") try: log_dir = WORKSPACE / "logs" since = datetime.now() - timedelta(days=days) for file in log_dir.rglob("*.log"): if not self._is_recent(file, since): continue with open(file) as f: content = f.read() # Find error patterns self._extract_error_patterns(content) ``` ```python def _extract_command_patterns(self, content): """Extract command patterns from content.""" # Look for command blocks command_blocks = re.findall(r"```bash\n(.*?)```", content, re.DOTALL) for block in command_blocks: commands = block.strip().split("\n") for cmd in commands: if cmd and not cmd.startswith("#"): pattern = self._generalize_command(cmd) self.patterns["commands"].append({ "pattern": pattern, "example": c ...[truncated 3583 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove raw examples from persistent output** - Do not store the original `cmd` or `error` values. - Retain only generalized patterns, counters, and non-sensitive aggregate statistics. 2. **Apply comprehensive secret redaction** - Before analysis or persistence, redact bearer tokens, API keys, passwords, cookies, authorization headers, private-key blocks, credential-bearing URLs, and secret environment variables. - Prefer an allowlist of acceptable data fields over a blacklist of secret patterns. 3. **Reduce collection scope** - Require explicit input paths or a documented allowlist. - Exclude private memory directories by default. - Avoid recursively scanning the entire memory and log trees unless the user explicitly enables that behavior. 4. **Protect stored output** - Create the pattern directory and files with restrictive permissions, such as owner-only access. - Use atomic file creation with explicit modes rather than relying on the process umask. - Consider encryption at rest when retained patterns may contain sensitive operational data. 5. **Implement retention controls** - Expire old patterns and examples automatically. - Limit file size and record count to prevent indefinite accumulation. - Provide a supported command to erase learned data. 6. **Improve transparency and consent** - Update `SKILL.md` to state exactly which directories are scanned, which data is extracted, how long it is retained, and where it is stored. - Require explicit opt-in before processing memory or logs that may contain private information. 7. **Add security tests** - Add tests using representative API keys, authorization headers, passwords, private keys, and credential-bearing URLs. - Verify that none of those values appear in `patterns.json` or application logs. ]]>
