T09 · Insecure Skill Coding Practices
- Location
scripts/search.py:121- Finding
Unsanitized API-Controlled URLs Can Inject Terminal Control Characters
- Content
View full analysis
Vulnerability Details
File Location:
scripts/search.py:22-26andscripts/search.py:121-124
Vulnerability Type: Incomplete output sanitization / terminal output injection
Risk Level: LowThe formatted output path sanitizes titles but prints API-provided URLs directly to the terminal.
python def sanitize_output(text: str) -> str: """Strip ANSI control codes and other potentially dangerous characters""" # Remove ANSI escape sequences ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') return ansi_escape.sub('', text)python for i, result in enumerate(results["results"], 1): title = sanitize_output(result.get('title', 'No title')) url = result.get('url', 'N/A') print(f"{i}. {title}") print(f" URL: {url}")Technical Analysis
Search-result fields originate from a remote API and ultimately from potentially attacker-controlled web content. The
titleandsnippetfields pass throughsanitize_output(), but theurlfield is printed without any sanitization or scheme validation.A URL containing terminal control characters could manipulate terminal presentation, overwrite displayed lines, or spoof adjacent output. Furthermore,
sanitize_output()only removes recognized ANSI escape sequences; it does not comprehensively remove unsafe C0/C1 control characters such as carriage return, backspace, or other display-affecting characters. This makes the documentation's broad claim that output sanitization prevents terminal injection inaccurate.Attack Path
- An attacker publishes or controls web content containing a crafted URL or metadata with terminal control characters.
- The content is indexed and returned by the Perplexity Search API as a result.
- The Skill decodes the API response without validating the result fields.
- In formatted output mode,
result.get('url', 'N/A')is assigned directly tourl. - `print(f ...[truncated 631 chars]
- Remediation
View remediation
Remediation Suggestions
-
Apply output sanitization to every untrusted formatted field, including URLs:
python url = sanitize_output(str(result.get("url", "N/A"))) -
Strengthen
sanitize_output()to remove unsafe C0 and C1 control characters while explicitly preserving only required whitespace:python def sanitize_output(value: object) -> str: text = str(value) text = ansi_escape.sub("", text) return "".join( char for char in text if char in "\t" or (ord(char) >= 0x20 and ord(char) != 0x7F) ) -
Validate result URLs with
urllib.parse.urlparseand permit only expected schemes such ashttpandhttps. Reject or visibly label malformed and unsupported URLs. -
Add regression tests covering ANSI escape sequences, carriage returns, line feeds, backspaces, null bytes, DEL, C1 controls, and unexpected non-string API values.
-
Update
SKILL.md,README.md, andSECURITY_AUDIT.mdso their security claims accurately describe the sanitizer's scope instead of asserting complete prevention of terminal injection.
-
