T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/analyze_logs.py:132
- Finding
- Terminal Escape-Sequence Injection Through Untrusted Log Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analyze_logs.py`, lines 132–136 and 178–181 **Vulnerability Type**: Improper neutralization of terminal control sequences **Risk Level**: Medium ### Vulnerable Code ```python if severity in ("FATAL", "ERROR", "WARN"): fp = fingerprint(stripped) error_groups[fp] += 1 if fp not in error_examples: error_examples[fp] = stripped[:500] ``` ```python for i, err in enumerate(result["top_errors"], 1): print(f"\n #{i} [{err['count']}x]") example = err["example"] if len(example) > 120: example = example[:117] + "..." print(f" {example}") ``` ### Technical Analysis Log entries are commonly influenced by untrusted remote input, such as HTTP headers, request paths, usernames, protocol values, or application error messages. The analyzer retains the original log text in `error_examples` and later prints it directly to the terminal. Truncating the string does not neutralize embedded ANSI, OSC, C0, or C1 terminal control sequences. If a malicious log entry contains such sequences, a compatible terminal may interpret them as commands rather than displaying them as ordinary text. The JSON output path uses `json.dumps()`, which escapes standard control characters. The vulnerable path is the default human-readable output generated by `print_report()`. ### Attack Path 1. An attacker supplies crafted input to an application or service that records attacker-controlled values in its logs. 2. The crafted value includes terminal control sequences and a severity keyword such as `ERROR`, causing the analyzer to retain it as an error example. 3. An operator invokes `python3 scripts/analyze_logs.py <logfile>` without the `--json` option. 4. The analyzer reads the malicious line, stores up to 500 characters of the raw content, and selects it as an example for a top error pattern. 5. `print_report()` writes the content directly to the operator's terminal. 6. The terminal ...[truncated 917 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Sanitize all untrusted strings before writing them to an interactive terminal: 1. Remove or visibly encode ANSI, OSC, C0, and C1 control sequences. 2. Preserve safe formatting characters only when necessary, such as converting tabs and newlines to visible escaped forms. 3. Apply sanitization at the output boundary in `print_report()` so every future terminal output field receives consistent protection. 4. Continue using `json.dumps()` for JSON output and avoid manually constructing JSON. 5. Add automated tests containing ESC (`\x1b`), BEL (`\x07`), carriage return (`\r`), backspace (`\b`), OSC sequences, and ANSI CSI sequences. 6. Document that logs should be treated as untrusted data. A defensive implementation could convert every non-printable character into a visible escape: ```python def sanitize_terminal(value: str) -> str: return "".join( ch if ch.isprintable() else f"\\x{ord(ch):02x}" for ch in value ) ``` Apply it immediately before terminal output: ```python example = sanitize_terminal(err["example"]) if len(example) > 120: example = example[:117] + "..." print(f" {example}") ``` For stronger coverage, use a well-tested terminal sanitization routine that explicitly handles complete ANSI CSI and OSC sequences rather than relying only on a narrow regular expression. ]]>
