T09 · Insecure Skill Coding Practices
- Location
scripts/competitor_watch.py:216- Finding
Terminal Control-Sequence Injection Through Untrusted Report Content
- Content
View full analysis
Vulnerability Details
File Location:
scripts/competitor_watch.py:216andscripts/competitor_watch.py:248-250
Vulnerability Type: Improper neutralization of terminal control sequences
Risk Level: MediumThe text report writes attacker-controlled competitor names and post content directly to the terminal without removing ANSI escape sequences or other control characters.
python w(f" phy-competitor-watch — {profile.name} Content Analysis")python for i, p in enumerate(profile.top_posts, 1): preview = p.text[:80].replace("\n", " ") w(f" {i}. [{p.engagement}] {preview}...") w(f" Topics: {', '.join(p.topics)} | Style: {', '.join(p.styles)}")Technical Analysis
profile.nameoriginates from the user-controlled--namecommand-line argument. The value ofp.textoriginates from the supplied JSON document. Both values can therefore contain arbitrary terminal control characters.The post preview removes newline characters, but it does not remove escape characters, ANSI control sequences, C0/C1 control characters, or terminal-specific Operating System Command sequences. When
print(format_report(profile))sends the generated report to an interactive terminal, the terminal can interpret these bytes as commands instead of displaying them as ordinary text.Depending on terminal capabilities and configuration, crafted input could clear or rewrite displayed output, move the cursor, forge apparently legitimate report or shell content, create deceptive hyperlinks, alter the window title, or interact with terminal features such as clipboard control. The script itself does not pass this content to a shell and does not provide a demonstrated arbitrary-code-execution primitive.
Attack Path
Competitor-name vector:
- An attacker or untrusted caller supplies a crafted
--namevalue containing terminal escape sequences. - The value is stored as
profile.name. - `f ...[truncated 1558 chars]
- An attacker or untrusted caller supplies a crafted
- Remediation
View remediation
Remediation Suggestions
Sanitize every untrusted value before writing it to a terminal, including
profile.name, post previews, and any future fields derived from imported data.- Remove ANSI escape sequences, C0/C1 control characters, and terminal-specific command sequences.
- Preserve only explicitly permitted whitespace, such as ordinary spaces and tabs.
- Apply sanitization at the terminal-output boundary rather than relying on individual callers.
- Keep JSON output available for machine processing, while ensuring downstream renderers safely escape untrusted strings.
- Add regression tests containing CSI, OSC, carriage return, backspace, and other control characters.
Example hardening:
python ANSI_ESCAPE = re.compile( r"\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])" ) def safe_terminal(value: str) -> str: value = ANSI_ESCAPE.sub("", value) return "".join( character for character in value if character == "\t" or ord(character) >= 0x20 )Use the sanitizer for every user-derived terminal field:
python safe_name = safe_terminal(profile.name) w(f" phy-competitor-watch — {safe_name} Content Analysis") preview = safe_terminal(p.text[:80].replace("\n", " ")) w(f" {i}. [{p.engagement}] {preview}...")For stronger guarantees, replace disallowed characters with visible escaped representations such as
\x1brather than silently deleting them. Consider a well-tested terminal sanitization implementation if reports may process fully hostile input.
