T09 · Insecure Skill Coding Practices
- Location
zhihu-hot.py:121- Finding
Unsanitized Remote Content Enables Terminal Escape-Sequence Injection
- Content
View full analysis
str: req = urllib.request.Request( url, headers=headers or {"User-Agent": "Mozilla/5.0 (compatible; ZhihuHotBot/3.0)"} ) with urllib.request.urlopen(req, timeout=30) as resp: return resp.read().decode("utf-8") ``` Parsed remote titles and URLs are stored unchanged: ```python for title, url in items: result["hot_search"].append({ "title": title, "url": url, "decoded_url": decode_url(url) }) ``` The resulting values are written directly to the terminal: ```python for i, item in enumerate(items, 1): title = item["title"] if get_display_width(title) > 38: title = title[:18] + ".." lines.append(f"│ {i:2d} │ {pad_string(title, 40)} │") ``` Other output paths similarly interpolate remote values without sanitization: ```python lines.append(f"{colorize(str(i).rjust(2), 'yellow')}. {item['title']}") ``` ```python lines.append(f" {i:2d}. {title} ({count}天)") ``` ### Technical Analysis The application treats Markdown retrieved from a remote GitHub repository as trusted display data. Titles, update times, and URLs extracted from that content can contain terminal control characters, including ANSI and OSC escape sequences. These characters are preserved by parsing and formatting and are subsequently emitted to the user's terminal. The existing `colorize` function only adds application-controlled ANSI sequences. It does not remove attacker-controlled control characters from remote values. Length truncation also does not provide protection because a malicious escape sequence can fit within the truncated portion. If the up ...[truncated 1672 chars]- Remediation
View remediation
str: value = ANSI_ESCAPE_RE.sub("", value) return "".join( ch for ch in value if ch in "\n\t" or (ord(ch) >= 0x20 and not 0x7F <= ord(ch) <= 0x9F) ) ``` For single-line fields, remove newlines and tabs as well. A mature terminal-sanitization library is preferable to a custom regular expression where available. ]]>
