Back to skill

Security audit

Partykeys Midi

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly aligned with controlling a PartyKeys MIDI keyboard, but it exposes an unauthenticated network hardware-control bridge and has risky setup behavior that should be reviewed before installation.

Install only if you are comfortable exposing a local hardware-control bridge. Run it on a trusted network or behind firewall rules, back up ~/.openclaw/mcp.json and ~/.openclaw/openclaw.json before setup, and prefer a version that binds to localhost or uses an explicit pairing token, pinned dependencies, and a safe config merge.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
server/mcp_server.py:31
Finding
Unauthenticated Network-Facing WebSocket Hardware Bridge<![CDATA[ ## Vulnerability Details **File Location**: `server/mcp_server.py:31-33`, `server/mcp_server.py:51-99`, and `server/mcp_server.py:115-132` **Vulnerability Type**: Unauthenticated remote access to a hardware-control service **Risk Level**: High ### Vulnerable Code ```python self._runner = web.AppRunner(self._app) await self._runner.setup() site = web.TCPSite(self._runner, '0.0.0.0', port) await site.start() ``` ```python async def _handle_ws(self, request): ws = web.WebSocketResponse() await ws.prepare(request) self._clients.add(ws) client_info = f"新客户端 (现有 {len(self._clients)} 个客户端)" print(f"[WS] {client_info}") try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: data = json.loads(msg.data) msg_type = data.get('type', '') if msg_type == 'status': ble = data.get('data', {}).get('bleConnected', False) bridge = data.get('data', {}).get('bridge', 'unknown') print(f"[WS] 状态更新:BLE={ble}, bridge={bridge}") gateway.ble_connected = ble if ble: gateway.mode = gateway.mode or "web" elif msg_type == 'command': cmd_id = data.get('id', '') self._pending[cmd_id] = ws print(f"[WS] 收到命令:{data.get('command', {})}") for client in self._clients: if client != ws and not client.closed: await client.send_json(data) print(f"[WS] 转发命令到客户端") elif msg_type == 'result': fid = data.get('id', '') requester_ws = self._pending.pop(fid, None) if requester_ws and not requester_ws.closed: await requester_ws.send_json(data) print(f"[WS] 转发结果给请求者") ...[truncated 2557 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind the service to `127.0.0.1` by default. Require an explicit, security-conscious configuration option before listening on external interfaces. 2. Generate an unpredictable, short-lived session token when the bridge starts and require it during the WebSocket handshake. 3. Authenticate clients and assign explicit roles, such as MCP requester, mobile bridge, or browser bridge. 4. Authorize each message type according to the authenticated client role. A bridge should not automatically be permitted to act as an arbitrary command requester. 5. Validate the `Origin` header for browser clients and reject unexpected origins. 6. Use `wss://` with a valid TLS configuration for remote or local-network deployment. 7. Validate incoming JSON against strict schemas, including bounded lengths, recognized commands, parameter types, and unique command identifiers. 8. Associate pending commands with the specific bridge client that received them and accept results only from that client. 9. Add connection limits, message-size limits, timeouts, and rate limiting. 10. Document firewall requirements and warn users before exposing port 18790 outside the loopback interface. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.sh:78
Finding
Destructive Replacement of Existing OpenClaw MCP Configuration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:78-100` **Vulnerability Type**: Unsafe configuration-file modification **Risk Level**: Medium ### Vulnerable Code ```bash if command -v jq &>/dev/null; then local tmp tmp=$(mktemp) jq --arg name "$MCP_NAME" \ --arg cmd "$PYTHON_BIN" \ --arg entry "$MCP_ENTRY" \ '.mcpServers[$name] = {"command": $cmd, "args": [$entry]}' \ "$MCP_JSON" > "$tmp" && mv "$tmp" "$MCP_JSON" echo "[✓] MCP server registered in $MCP_JSON" else cat > "$MCP_JSON" << MCPEOF { "mcpServers": { "$MCP_NAME": { "command": "$PYTHON_BIN", "args": ["$MCP_ENTRY"] } } } MCPEOF echo "[✓] MCP server written to $MCP_JSON" echo " (⚠ jq not found — existing entries in mcp.json may have been overwritten)" fi ``` ### Technical Analysis When `jq` is unavailable, the setup script uses shell output redirection with `>` to truncate and replace `$HOME/.openclaw/mcp.json`. It does not first preserve existing MCP registrations, create a backup, request confirmation, or abort safely. Writing this configuration is necessary to register the Skill, but replacing the entire file exceeds the minimum write scope required. The warning appears only after the destructive operation has already occurred. ### Attack Path 1. A user follows the installation instructions and runs `bash scripts/setup.sh`. 2. The target environment has Python but does not have `jq`. 3. The script enters the fallback branch. 4. `cat > "$MCP_JSON"` truncates the existing MCP configuration. 5. The script writes a new file containing only the PartyKeys MCP registration. 6. Existing MCP server registrations and unrelated configuration entries are lost. No external attacker interaction is required; this is a deterministic destructive installation path on systems without `jq`. ### Impact Assessment The script runs with the invoking user's permissions and can alter files in that user's OpenClaw configuration directory ...[truncated 434 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use Python's standard `json` module as a safe fallback so that existing JSON content is parsed and merged rather than replaced. 2. Update only `.mcpServers.partykeys`; preserve all unrelated keys and registrations. 3. Create a timestamped backup with restrictive permissions before modifying an existing configuration file. 4. Write the merged configuration to a temporary file in the same directory, validate it as JSON, set appropriate permissions, and then atomically rename it. 5. Abort without changing the original file if parsing, validation, or writing fails. 6. Preserve or deliberately harden the original file's ownership and permission mode. 7. Inform the user before making destructive or structurally incompatible changes rather than warning only afterward. 8. Provide an uninstall operation that removes only the `partykeys` registration. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/setup.sh:50
Finding
Unpinned Runtime Dependency Installation and Incomplete Dependency Declaration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:50-51`; supporting declarations at `server/requirements.txt:1-2` and import at `server/script_ble_client.py:5` **Vulnerability Type**: Mutable and incomplete third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash echo "Installing Python dependencies..." "$VENV_DIR/bin/pip" install --quiet --upgrade pip "$VENV_DIR/bin/pip" install --quiet mcp aiohttp ``` The provided requirements file also permits unrestricted future versions: ```text mcp>=1.0.0 aiohttp>=3.9.0 ``` The BLE implementation imports another package that is not installed by the setup script or declared in the requirements file: ```python from bleak import BleakClient, BleakScanner ``` ### Technical Analysis The setup process installs the latest versions of `mcp` and `aiohttp` available at installation time and upgrades `pip` without exact version constraints or artifact hashes. Consequently, the code reviewed in this package does not fully determine the code that will execute after installation. Python package installation may execute package build or installation logic with the permissions of the invoking user. If an upstream account, release, package index, or dependency is compromised, a future installation can execute altered code even though the Skill itself has not changed. The script also ignores the bundled `requirements.txt`, while both that file and the direct installation command omit `bleak`. Because `mcp_server.py` imports `ScriptBLEClient` unconditionally and that module imports `bleak`, a clean environment can fail before the MCP server starts. ### Attack Path Supply-chain exploitation path: 1. A user runs the documented setup script. 2. The script connects to the configured Python package index and resolves mutable current releases. 3. No lock file or hashes constrain which artifacts are accepted. 4. A compromised upstream package or transitive dependency is downloaded an ...[truncated 993 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Maintain a reviewed lock file containing exact versions for all direct and transitive dependencies. 2. Include cryptographic hashes and install with `pip --require-hashes`. 3. Install from the lock file rather than duplicating dependency names directly in `setup.sh`. 4. Add a reviewed, pinned version of `bleak` if script-mode BLE support remains enabled. 5. Alternatively, import `bleak` lazily only when script mode is selected and return a clear dependency error if it is unavailable. 6. Avoid automatically upgrading `pip`; if an upgrade is required, pin and verify the intended version. 7. Use a trusted package index configuration and prevent unintended fallback to untrusted indexes. 8. Add automated dependency vulnerability scanning and controlled update review. 9. Test installation and startup in a clean environment to verify that the declared dependency set is complete and reproducible. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the implementation performs BLE scanning/connection or claims listening/follow features that are not accurately represented, the skill creates a trust and consent problem around nearby-device access and actual behavior. Hidden or inaccurately described hardware access is security-relevant because Bluetooth discovery and connection can expose local devices and exceed user expectations.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
If the implementation performs BLE scanning/connection or claims listening/follow features that are not accurately represented, the skill creates a trust and consent problem around nearby-device access and actual behavior. Hidden or inaccurately described hardware access is security-relevant because Bluetooth discovery and connection can expose local devices and exceed user expectations.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
result["message"] = f"已通过脚本连接设备:{result['address']}"
        else:
            # 未指定模式或指定 mobile/web 时,返回统一的连接提示
            local_ip = subprocess.run(
                "ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -1",
                shell=True, capture_output=True, text=True
            ).stdout.strip() or "<本机 IP>"
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding
The skill advertises executable setup and clearly relies on networked WebSocket control, yet it does not declare any explicit tool scope such as allowed tools or permissions. That omission weakens reviewability and policy enforcement because consumers cannot easily see that shell execution and network access are part of the skill's operation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The natural-language instructions, headings, and usage guidance are all presented in Chinese, which effectively forces a specific language for users of the skill. Under the policy, language constraints should be optional or clearly justified as region-specific; neither is stated here.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Natural-language strings and descriptions in the file are presented exclusively in Chinese, including the module description and user-facing tool descriptions/messages. The file does not offer a language choice or explain that the skill is intentionally region- or locale-specific, which can violate language/locale policy requirements.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The server binds a WebSocket service to 0.0.0.0:18790 and accepts arbitrary clients with no authentication, authorization, origin checks, or session binding. Any reachable client can connect, send status/command/result frames, and participate in relaying control messages to other clients and potentially attached hardware.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Exposing an unauthenticated command-and-control WebSocket service on all interfaces is dangerous because users may unknowingly make hardware control reachable from other hosts on the LAN or beyond. In this skill's context, the service is specifically meant to bridge remote commands to a physical MIDI device, which increases the practical risk of unauthorized control and traffic interception.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Incoming WebSocket messages of type command and result are forwarded among connected clients without trust boundaries, message authentication, or confidentiality controls. This allows one client to inject spoofed commands/results, observe or influence another client's session, and potentially capture device-related activity or user interaction data.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
result["message"] = f"已通过脚本连接设备:{result['address']}"
        else:
            # 未指定模式或指定 mobile/web 时,返回统一的连接提示
            local_ip = subprocess.run(
                "ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -1",
                shell=True, capture_output=True, text=True
            ).stdout.strip() or "<本机 IP>"
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes controlling the PartyKeys MIDI keyboard via WebSocket, including listening to playing and follow mode for music teaching. This module instead scans for nearby BLE devices and connects directly over Bluetooth, and its follow mode contains a TODO rather than real MIDI input listening, so the implemented behavior does not match the described interface and capabilities.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The function is documented as '跟弹模式' (follow-play mode), which implies reacting to a user's played notes. In practice, it only lights each note, sleeps briefly, and appends success=True for every note, while the inline TODO explicitly acknowledges that MIDI input listening is not implemented.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
Line L128 tells the user to test the skill with a specific Chinese-language phrase, which imposes a language expectation in natural-language instructions. There is no indication that the skill is region-specific or that users may use another language, so this conflicts with the policy against forcing a specific language without opt-in.

Description-Behavior Mismatch

Low
Confidence
89% confidence
Finding
The manifest says the skill can connect the device, light keys, listen to playing, play sequences, and provide follow mode for teaching. The tool list additionally implements changing device mode, octave, BPM, beat type, skin, querying firmware version, and querying device presence, which materially exceeds the narrower feature set claimed in the manifest description.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The skill executes a shell command via subprocess.run(..., shell=True) to inspect host network configuration. While this may be part of connection setup, this file does not provide a direct warning or disclosure that system shell commands will be executed on the host.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The code starts the WebSocket server on port 18790, but the user-facing instructions for the GitHub Pages/Vercel connection path tell users to connect to ws://{local_ip}:9528/ws. This is an active contradiction in inline user guidance, not merely an omission.

Unpinned Dependencies

Low
Category
Supply Chain
Content
mcp>=1.0.0
aiohttp>=3.9.0
Confidence
96% confidence
Finding
The dependency `mcp>=1.0.0` is not pinned to an exact version, which makes builds non-reproducible and can silently introduce vulnerable or incompatible releases during installation. Because `mcp` also has known advisories, leaving the version open increases supply-chain risk and makes it impossible to verify whether deployed environments are affected.

Unverifiable Dependency: mcp has 12 known advisory(ies) (CVE-2025-53366 (MCP Python SDK vulnerability in the FastMCP Server causes validation error, lead); CVE-2025-66416 (Model Context Protocol (MCP) Python SDK does not enable DNS rebinding protection); CVE-2026-52870 (MCP Python SDK: Experimental task handlers allow any client to access and cancel) +9 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding
`mcp` has multiple known advisories, and because the manifest does not pin a version, there is no reliable way to determine whether installs will pull a vulnerable release. In an agent skill context, `mcp` is part of the protocol/server surface, so dependency uncertainty on this package is more dangerous than a purely local utility library.

Unpinned Dependencies

Low
Category
Supply Chain
Content
mcp>=1.0.0
aiohttp>=3.9.0
Confidence
96% confidence
Finding
The dependency `aiohttp>=3.9.0` is not pinned to a specific version, so future installs may resolve to different releases with different security properties. This creates a supply-chain and reproducibility problem, especially for a network-facing component likely using `aiohttp` for HTTP or WebSocket handling.

Unverifiable Dependency: aiohttp has 16 known advisory(ies) (CVE-2024-52303 (aiohttp has a memory leak when middleware is enabled when requesting a resource ); CVE-2026-54279 (aiohttp: Host-Only Cookies Become Domain Cookies After CookieJar Persistence); CVE-2026-34514 (AIOHTTP has CRLF injection through multipart part content type header constructi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding
`aiohttp` has known security advisories, and the unpinned requirement means different environments may install versions that are vulnerable without visibility or control. Since this skill exposes WebSocket/network functionality, weaknesses in `aiohttp` can directly affect remote attack surface and therefore raise the practical risk.

Missing User Warnings

Low
Confidence
80% confidence
Finding
The code scans nearby Bluetooth devices and connects to a selected address, which involves interacting with external devices and collecting nearby device identifiers. Aside from terse Chinese docstrings, there is no user-facing prompt, log, or comment warning that device discovery and connection will occur.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The skill sends initialization and lighting commands to a Bluetooth device via write_gatt_char, which changes device state. The code contains no user-facing warning, confirmation, or explanatory logging that commands will be transmitted to the external device.

Static analysis

No suspicious patterns detected.