T09 · Insecure Skill Coding Practices
Warning
- Location
- lean-report.py:558
- Finding
- Unsanitized Audited Data Enables Terminal Escape-Sequence Injection<![CDATA[ ## Vulnerability Details **File Location**: `lean-report.py:187`, `lean-report.py:230-231`, `lean-report.py:277-294`, and `lean-report.py:558-567` **Vulnerability Type**: Terminal escape-sequence injection through untrusted report fields **Risk Level**: Medium ### Vulnerable Code Cron job names and IDs are read from the audited installation without sanitization: ```python name = job.get("name", job.get("id", "unknown"))[:50] ``` The untrusted value is incorporated into report findings and remediation metadata: ```python if issues: for issue in issues: results["findings"].append(("warn", f" [{name}] {issue}")) results["issues"].append({"job": name, "issue": issue}) else: results["findings"].append(("pass", f" [{name}] model={model} thinking={thinking} ✓")) ``` Session-store keys are similarly incorporated into findings without sanitization: ```python is_main = key.endswith(":main") # Flag bloated non-main sessions if pct >= 40 and not is_main: penalties += 8 results["waste_tokens"] += tokens results["findings"].append(("fail", f" {key}: {pct}% ({tokens:,} tokens) — bloated")) results["stale"] += 1 elif pct >= 25 and age_hours > 24 and not is_main: penalties += 4 results["waste_tokens"] += tokens results["findings"].append(("warn", f" {key}: {pct}% ({tokens:,} tokens), {age_hours:.0f}h stale")) results["stale"] += 1 elif pct >= 60 and is_main: penalties += 5 results["findings"].append(("warn", f" {key}: {pct}% — main session running hot")) ``` The resulting messages are written directly to an ANSI-capable terminal: ```python for level, msg in audit["findings"]: if level == "fail": print(f" {RED}✗{RESET} {msg}") elif level == "warn": print(f" {YELLOW}⚠{RESET} {msg}") elif level == "pass": print(f" {GREEN}✓{RESET} {msg}") else: print(f" {DIM}ℹ{RESET} {msg}") ``` ### Technical Analysis Cron names, cron IDs, and se ...[truncated 2401 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Introduce a terminal-output sanitizer and apply it to every string derived from audited files before rendering: ```python import re import unicodedata ANSI_ESCAPE_RE = re.compile( r""" \x1B (?: \[[0-?]*[ -/]*[@-~] # CSI | \][^\x07\x1B]*(?:\x07|\x1B\\) # OSC | [PX^_][^\x1B]*(?:\x1B\\) # DCS/SOS/PM/APC | [@-_] # Two-character escape ) """, re.VERBOSE, ) def safe_terminal_text(value): text = str(value) text = ANSI_ESCAPE_RE.sub("", text) return "".join( ch for ch in text if ch in "\t\n" or unicodedata.category(ch) not in {"Cc", "Cf"} ) ``` 2. Sanitize values at the output boundary rather than relying only on individual audit checks: ```python safe_msg = safe_terminal_text(msg) print(f" {YELLOW}⚠{RESET} {safe_msg}") ``` 3. Also sanitize cron names and session keys when creating findings. This provides defense in depth and prevents unsafe values from reaching other text-output paths such as `print_fixes()`. 4. Avoid permitting carriage returns in terminal messages because they can overwrite the current line. If multiline values are unnecessary, replace all newlines and tabs with visible escaped representations as well. 5. Keep raw values in structured JSON output only when required. Continue using `json.dumps()` so control characters remain JSON-escaped. 6. Add tests containing CSI cursor movement, screen-clearing sequences, OSC hyperlinks, OSC title changes, carriage returns, backspaces, and malformed escape sequences. Verify that human-readable output contains no untrusted control bytes. ]]>
