Back to skill

Security audit

Skillsmp Search

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward SkillsMP marketplace search helper, but users should be aware it sends searches to SkillsMP with an API key and prints remote result text directly in the terminal.

Install this only if you are comfortable giving it a SkillsMP API key and sending your search terms to SkillsMP. Treat displayed marketplace results as untrusted text, and be cautious with copied links or instructions until the script sanitizes terminal control characters and the documentation is corrected to match implemented features.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

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. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
代码的核心功能与“搜索 SkillsMP 市场中的技能”这一总体描述基本一致,因此不存在完全不同的主要目的。但声明中特别写到“支持关键词搜索和 AI 语义搜索”,而实际实现只接受一个查询字符串并调用单一搜索接口,没有看到语义搜索模式、向量检索、模型推理或单独的语义搜索参数/端点,因此该能力描述与实现不符。此外,虽然访问 SkillsMP API 属于实现该功能的合理细节,但声明的 permissions 为空,实际代码却依赖 API key 并访问外部网络;这构成对资源访问方式的未说明差异。综合判断,描述未准确反映代码行为,属于能力层面的轻中度不匹配。

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The natural-language content in the description and usage sections is consistently Chinese, and the file does not indicate that the skill is region-specific or provide an opt-in language alternative. This can violate language/locale policy when users are not given a choice of interface language.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The script presents usage text in Chinese at L19, and later emits additional Chinese-only output strings. This imposes a specific language on users without offering a language choice or documenting a justified region-specific constraint, which matches the locale policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
Lines L66-L81 contain several hard-coded Chinese UI strings such as result headers and field labels. Because the file does not offer opt-in, locale detection, or documented justification for Chinese-only behavior, this is a natural-language policy violation.

Static analysis

No suspicious patterns detected.