T09 · Insecure Skill Coding Practices
Warning
- Location
- search.sh:48
- Finding
- Unsanitized Remote Content Can Inject Terminal Control Sequences<![CDATA[ ## Vulnerability Details **File Location**: `search.sh`, lines 48-85 **Vulnerability Type**: Terminal control-sequence injection through untrusted API content **Risk Level**: Medium ### Vulnerable Code ```bash # Parse and display results echo "$RESPONSE" | python3 -c " import sys, json try: data = json.load(sys.stdin) except: print('Error: Invalid JSON response') sys.exit(1) skills = data.get('data', {}).get('skills', []) if not skills: print('No results found') sys.exit(0) total = data.get('data', {}).get('pagination', {}).get('total', len(skills)) print('='*60) print(f'找到 {total} 个 Skills (显示前 {len(skills)} 个):') print('='*60) for i, skill in enumerate(skills, 1): name = skill.get('name', 'N/A') description = skill.get('description', '')[:70] author = skill.get('author', 'N/A') stars = skill.get('stars', 0) url = skill.get('skillUrl', '') print(f'') print(f'{i}. {name}') print(f' 作者: {author}') print(f' ⭐: {stars}') print(f' 描述: {description}...') print(f' 链接: {url}') print('') print('='*60) " 2>/dev/null || echo "$RESPONSE" ``` ### Technical Analysis The script treats fields returned by the remote SkillsMP API as trusted terminal text. Values such as `name`, `description`, `author`, and `skillUrl` are decoded from JSON and printed without filtering control characters. JSON escape sequences such as `\u001b` are converted into actual escape bytes by `json.load`. If a marketplace record or API response contains ANSI terminal control sequences, printing these fields can cause the user's terminal emulator to interpret them rather than display them literally. The error fallback creates an additional exposure because `echo "$RESPONSE"` writes the complete, untrusted response directly to the terminal when the Python command fails. This fallback does not require the response to be valid JSON. This is a display-layer injection issue. The reviewed code does not establish ...[truncated 1467 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Sanitize every remotely supplied field before writing it to a terminal. Remove C0 and C1 control characters, including escape bytes, while optionally preserving explicitly permitted whitespace. ```python import re CONTROL_CHARS = re.compile( r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]' ) def terminal_safe(value): if not isinstance(value, str): value = str(value) return CONTROL_CHARS.sub('', value) ``` Apply the function to all remote values: ```python name = terminal_safe(skill.get('name', 'N/A')) description = terminal_safe(skill.get('description', ''))[:70] author = terminal_safe(skill.get('author', 'N/A')) stars = terminal_safe(skill.get('stars', 0)) url = terminal_safe(skill.get('skillUrl', '')) ``` 2. Do not print the raw API response when parsing fails. Return a fixed error message to standard error instead: ```bash " || { echo "Error: Unable to parse the SkillsMP API response" >&2 exit 1 } ``` 3. Avoid suppressing all Python diagnostics with `2>/dev/null`. Log a controlled diagnostic message so parsing failures can be investigated without exposing raw, attacker-controlled content. 4. Consider an output mode that serializes data safely, such as JSON generated by a trusted encoder, for callers that do not require human-readable terminal output. 5. Add regression tests containing ANSI escape bytes, C0/C1 control characters, malformed JSON, and multiline marketplace fields to verify that no untrusted control characters reach terminal output. ]]>
