Back to skill

Security audit

Clash Controller

Security checks for vulnerabilities and agentic risk

Overview

This skill is meant to control a local Clash proxy, but it embeds a controller secret and can change proxy routing from broad, ambiguous commands without confirmation.

Review this before installing. It is not evidence of malware, but it can alter local proxy routing and includes a built-in Clash controller secret. Install only if you understand the Clash REST controller setup, rotate or replace the secret, keep the controller bound to localhost, and use explicit commands because ambiguous phrasing can change routing unexpectedly.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
skill.js:3
Finding
Hard-Coded Clash REST API Bearer Secret<![CDATA[ ## Vulnerability Details **File Location**: `skill.js:3-14` **Vulnerability Type**: Hard-coded authentication credential **Risk Level**: Medium ### Vulnerable Code ```javascript const secret = 'ff62c2da-1504-446b-986f-f13ba034e8a5'; const port = 61222; function request(path, method = 'GET', body = null) { return new Promise((resolve, reject) => { const options = { hostname: '127.0.0.1', port: port, path: path, method: method, headers: { 'Authorization': `Bearer ${secret}`, 'Content-Type': 'application/json' } }; ``` ### Technical Analysis The Clash REST API bearer secret is embedded directly in the distributed source code. It is automatically attached to every API request made by the skill. A source-level credential cannot remain confidential because any user, process, archive recipient, repository reader, or package consumer with access to the project can recover it. The exposure is especially significant if this credential is also present in a live Clash configuration. The code currently connects only to `127.0.0.1`, which limits direct remote exploitation by this skill. Nevertheless, the exposed credential could be reused independently if the Clash external controller is accessible through another interface, port-forwarding arrangement, local malware, or a separate network configuration. ### Attack Path 1. An attacker obtains a copy of the project, package, repository, or source archive. 2. The attacker reads the bearer secret from `skill.js:3`. 3. The attacker identifies a running Clash controller configured with the same secret. 4. The attacker reaches that controller locally or through an exposed controller interface, tunnel, proxy, or port forward. 5. The attacker submits authenticated Clash API requests using the recovered bearer secret. 6. Within the permissions offered by the Clash API, the attacker reads proxy state or modifies proxy selection and related controller-man ...[truncated 726 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the bearer secret from the source code and package history. 2. Rotate the exposed secret in the active Clash configuration. 3. Load the secret at runtime from a protected environment variable, operating-system credential store, or permission-restricted configuration file. 4. Fail closed when the secret is absent rather than using a built-in default. 5. Keep the external controller bound to `127.0.0.1` unless remote access is explicitly required. 6. If remote access is required, place the controller behind authenticated, encrypted, and network-restricted access controls. 7. Restrict access to the runtime secret according to least privilege and prevent it from being written to logs or returned in errors. 8. Add secret-scanning checks to version-control and release pipelines. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
skill.js:49
Finding
Overly Broad Substring Matching Can Trigger Unintended Proxy Changes<![CDATA[ ## Vulnerability Details **File Location**: `skill.js:49-57` **Vulnerability Type**: Ambiguous command parsing and unsafe state-changing dispatch **Risk Level**: Medium ### Vulnerable Code ```javascript // 开启代理 if (args.includes('开启') || args.includes('启动') || args.includes('开') || args.includes('on') || args.includes('打开') || args.includes('代理开启')) { try { await request('/proxies/GLOBAL', 'PUT', { name: '自动选择' }); return '✅ 已开启代理(自动选择)'; } catch(e) { return '❌ 开启失败: ' + e.message; } } ``` Related state-changing branches use similarly broad matching: ```javascript // 关闭代理 if (args.includes('关闭') || args.includes('停止') || args.includes('关') || args.includes('off') || args.includes('代理关闭')) { try { await request('/proxies/GLOBAL', 'PUT', { name: 'DIRECT' }); return '✅ 已关闭代理(DIRECT)'; } catch(e) { return '❌ 关闭失败: ' + e.message; } } // 切换节点 if (args.includes('切换') || args.includes('换') || args.includes('节点')) { try { await request('/proxies/GLOBAL', 'PUT', { name: '自动选择' }); return '✅ 已切换到自动选择'; } catch(e) { return '❌ 切换失败: ' + e.message; } } ``` ### Technical Analysis The command dispatcher authorizes state-changing operations by checking whether arbitrary input contains short, non-exclusive substrings. In particular, the English token `on` can appear inside many unrelated words, while the single-character checks are also too broad to establish explicit user intent. Once any token matches, the skill immediately sends an authenticated `PUT` request to `/proxies/GLOBAL`. There is no exact command grammar, ambiguity rejection, confirmation step, or separation between read-only and state-changing intents. Branch ordering also creates incorrect behavior. The node-switching branch at lines 71-79 matches every command containing the node keyword before the node-list branch at lines 82-90 can run. A request intended to list nodes ...[truncated 1574 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace substring checks with an explicit command parser and a small allowlist of supported intents. 2. Use exact or anchored matching after normalizing whitespace and punctuation. 3. Do not use short generic tokens such as `on`, `off`, or individual characters as sufficient authorization for state changes. 4. Separate read-only commands from mutating commands and evaluate specific intents before generic ones. 5. Ensure that node-list requests are handled by the listing branch and cannot fall into the node-switching branch. 6. Reject commands that match multiple intents instead of selecting the first branch silently. 7. Require explicit confirmation before changing proxy routing when the input is generated by or relayed through an untrusted natural-language component. 8. Add tests for unrelated words containing `on` or `off`, negated requests, node-list requests, ambiguous commands, and mixed-language input. 9. Return the interpreted action before execution or expose typed API methods such as `enableProxy()`, `disableProxy()`, and `listNodes()` rather than accepting unrestricted text at the security boundary. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill metadata describes routine proxy control, but the finding indicates the underlying behavior accesses a sensitive local control interface with a hardcoded API secret and performs actions not clearly disclosed. Description-behavior mismatch is dangerous because users may authorize benign-sounding actions without understanding that the skill can reconfigure local network routing and query node information through privileged local APIs.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger phrases include broad terms like '代理' and '状态', which can match ordinary conversation and unintentionally invoke a skill that changes proxy behavior. In this context, accidental activation is security-relevant because the skill affects local network configuration and could disrupt traffic routing or privacy expectations without a deliberate user request.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The example phrases for status and node switching are short and ambiguous, lacking constraints that ensure the user intends to invoke this specific proxy-control skill. Because the skill can alter routing behavior, ambiguous examples increase the chance of unintended invocation and unreviewed changes to a sensitive local networking component.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The skill performs authenticated state-changing requests against a local privileged service and includes a hardcoded bearer token, allowing anyone who can invoke the skill to alter proxy routing without an explicit warning or confirmation step. In this context, changing proxy behavior can silently redirect or disable network traffic paths for the user, making the action security-relevant rather than a harmless preference change.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The command handling and responses are primarily written in Chinese, including trigger terms and output messages, while also partially mixing English terms. There is no indication that the skill is intentionally limited to a Chinese-speaking context or that users can choose another language, which may violate a language/locale policy requiring opt-in or justification.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest description says the skill controls Clash for Windows by '启动、关闭' (start/stop), and the user-facing strings also say '启动 Clash' and '停止 Clash'. In code, the '开启/启动' path only sends PUT /proxies/GLOBAL with name '自动选择', while the '关闭/停止' path switches GLOBAL to 'DIRECT'; this changes routing behavior but does not actually start or stop the Clash process.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The comments label the branches as '开启代理' and '关闭代理', and the usage text says '启动 Clash' and '停止 Clash'. However, those branches only write to /proxies/GLOBAL to select '自动选择' or 'DIRECT', so the documentation actively overstates what the code does.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The skill's natural-language interface, examples, and trigger phrases are presented only in Chinese, with no indication that the user may choose another language or locale. Under the stated policy, a fixed language without opt-in can be a locale-policy issue unless clearly documented as region-specific.

Static analysis

No suspicious patterns detected.