Back to skill

Security audit

Mopidy Party Mode

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly purpose-aligned, but its helper exposes host-level playback controls and a play-now command that silently clears the shared queue.

Install only if you trust the calling agent to enforce host approval and you are comfortable with the helper being able to change playback and clear the queue. Prefer a version that removes curl -k, separates guest-safe queue actions from host-only controls, and makes any queue-clearing action explicit and separately approved.

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
scripts/mopidy.sh:50
Finding

TLS Certificate Verification Disabled for Mopidy JSON-RPC Requests

Content
View full analysis
&2; exit 1; } jq -nc --arg q "$q" '{jsonrpc:"2.0",id:1,method:"core.library.search",params:{query:{any:[$q]},uris:null,exact:false}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" ;; add-track) uri="${1:-}" [ -n "$uri" ] || { echo "track uri required" >&2; exit 1; } jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" ;; add-album) uri="${1:-}" [ -n "$uri" ] || { echo "album uri required" >&2; exit 1; } jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" ;; add-playlist-to-queue) uri="${1:-}" [ -n "$uri" ] || { echo "playlist uri required" >&2; exit 1; } lookup=$(jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.playlists.lookup",params:{uri:$uri}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL") uris=$(printf '%s' "$lookup" | jq '[.result.tracks[].uri]') jq -nc --argjson uris "$uris" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:$uris}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" ;; play-track) uri="${1:-}" [ -n "$uri" ] || { echo "track uri required" >&2; exit 1; } rpc '{"jsonrpc":"2.0","id":1,"method":"core.tracklist.clear"}' >/dev/null jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" >/dev/null rpc '{"jsonrpc":"2.0","id":1,"method":"core.playback.play"}' ;; ``` ### Technical Analysis The `-k` option instructs `curl` to accept an HTTPS ...[truncated 1976 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mopidy.sh:77
Finding

The play-track Command Silently Clears the Entire Queue

Content
View full analysis
&2; exit 1; } rpc '{"jsonrpc":"2.0","id":1,"method":"core.tracklist.clear"}' >/dev/null jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" >/dev/null rpc '{"jsonrpc":"2.0","id":1,"method":"core.playback.play"}' ;; ``` ### Technical Analysis The `play-track` command performs three operations: it clears the complete track list, adds one URI, and starts playback. Its name only communicates immediate playback of a selected track; it does not disclose that all existing queue entries will be deleted. The skill policy treats “clear queue” and “play a specific track immediately” as distinct host-controlled actions. Therefore, host authorization to play a track immediately does not unambiguously authorize deletion of the shared queue. This mismatch between the advertised action and the implementation can cause a destructive operation without informed approval. The queue clear is also performed before the add operation succeeds. If adding the requested URI fails because of a network, backend, URI, or JSON-RPC error, the original queue has already been lost. ### Attack Path 1. Party guests contribute tracks to the shared queue. 2. The host approves a request to play one specific track immediately. 3. The agent or operator invokes `scripts/mopidy.sh play-track `. 4. The script calls `core.tracklist.clear`, silently deleting every existing queue entry. 5. It then attempts to add the requested URI and starts playback. 6. If the add operation fails, the queue remains empty; if it succeeds, all previous selections are still permanently rem ...[truncated 867 chars]
Remediation
View remediation
``` 4. Validate the URI and confirm that the add operation can succeed before deleting existing entries. Where supported, save the current queue and restore it if a later operation fails. 5. Split actions into narrowly scoped commands: - `add-track` for queue contribution; - `play-existing-track` for immediate playback without deletion; - `clear` for explicitly authorized queue deletion. 6. Enforce host authorization in the trusted orchestration layer before exposing playback or destructive commands. Do not rely solely on natural-language instructions when untrusted users may have direct access to the helper script. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The finding indicates the underlying scripts expose unrestricted playback-control operations, including play, pause, next, previous, clear, and a stronger play-track flow that clears the queue and starts playback immediately. That directly contradicts the skill's promise that guests cannot perform disruptive actions and that host approval is required, so a user could invoke damaging controls under false assumptions of safety.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The finding indicates the underlying scripts expose unrestricted playback-control operations, including play, pause, next, previous, clear, and a stronger play-track flow that clears the queue and starts playback immediately. That directly contradicts the skill's promise that guests cannot perform disruptive actions and that host approval is required, so a user could invoke damaging controls under false assumptions of safety.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script exposes disruptive playback commands (play, pause, next, previous, clear) even though the skill is explicitly described as party mode where guests may add music but must not control playback. In an agent setting, those commands create an authorization mismatch that lets guest-triggered requests disrupt the listening session or override the host’s control expectations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

play-track is more dangerous than a simple add-to-queue action because it clears the queue, inserts a chosen track, and starts playback immediately. That behavior directly defeats the skill’s stated shared-queue purpose and enables takeover of the session by any caller who can access the skill through the agent.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes shell-capable helper scripts and documents executable commands, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates unnecessary ambient authority: an agent may be able to execute broader shell actions than the skill actually needs, increasing the blast radius if the skill is misused or prompt-injected.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/match_top_tracks.py (reported line 21)May include surrounding context.

python
for song in songs:
    query = f"{artist} {song}"
    try:
        raw = subprocess.check_output(base_cmd + [query], text=True)
        data = json.loads(raw)
        tracks = data.get("result", [{}])[0].get("tracks", [])
    except Exception:

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 12)May include surrounding context.

sh
rpc() {
  local payload="$1"
  curl -sS -H 'Content-Type: application/json' -d "$payload" "$MOPIDY_URL"
}

usage() {

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The search path uses curl -k, which disables TLS certificate verification when sending user queries to the Mopidy endpoint. That allows a man-in-the-middle attacker on the network to intercept or tamper with requests and responses, making the remote-control channel less trustworthy.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 54)May include surrounding context.

sh
search)
    q="${*:-}"
    [ -n "$q" ] || { echo "search query required" >&2; exit 1; }
    jq -nc --arg q "$q" '{jsonrpc:"2.0",id:1,method:"core.library.search",params:{query:{any:[$q]},uris:null,exact:false}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL"
    ;;
  add-track)
    uri="${1:-}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The add-track command transmits requests with curl -k, disabling certificate validation for a control operation that changes the queue. An attacker able to intercept traffic could modify the requested URI or spoof responses, undermining integrity of the party-mode session.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 59)May include surrounding context.

sh
add-track)
    uri="${1:-}"
    [ -n "$uri" ] || { echo "track uri required" >&2; exit 1; }
    jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL"
    ;;
  add-album)
    uri="${1:-}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The add-album operation also uses curl -k, meaning album-add requests are sent over a TLS connection that does not authenticate the server. This exposes both request confidentiality and, more importantly, command integrity to interception or redirection attacks.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 64)May include surrounding context.

sh
add-album)
    uri="${1:-}"
    [ -n "$uri" ] || { echo "album uri required" >&2; exit 1; }
    jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL"
    ;;
  add-playlist-to-queue)
    uri="${1:-}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The playlist lookup request is sent with curl -k, allowing an active attacker to spoof the Mopidy server and return manipulated playlist contents. Because the result is later parsed and used to enqueue tracks, tampering here can directly alter what gets added to the queue.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 69)May include surrounding context.

sh
add-playlist-to-queue)
    uri="${1:-}"
    [ -n "$uri" ] || { echo "playlist uri required" >&2; exit 1; }
    lookup=$(jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.playlists.lookup",params:{uri:$uri}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL")
    uris=$(printf '%s' "$lookup" | jq '[.result.tracks[].uri]')
    jq -nc --argjson uris "$uris" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:$uris}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL"
    ;;

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The subsequent tracklist.add request in the playlist flow also uses curl -k, preserving the same man-in-the-middle risk for the queue-modification step. Combined with the insecure lookup, this creates an end-to-end unauthenticated control path for adding playlist tracks.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 71)May include surrounding context.

sh
[ -n "$uri" ] || { echo "playlist uri required" >&2; exit 1; }
    lookup=$(jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.playlists.lookup",params:{uri:$uri}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL")
    uris=$(printf '%s' "$lookup" | jq '[.result.tracks[].uri]')
    jq -nc --argjson uris "$uris" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:$uris}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL"
    ;;
  play)
    rpc '{"jsonrpc":"2.0","id":1,"method":"core.playback.play"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

Within play-track, the request that adds the chosen track uses curl -k, so the immediate-play path relies on an unauthenticated TLS session. In this context the risk is amplified because the surrounding command already clears the queue and starts playback, so tampering can directly influence disruptive host-visible actions.

Content

Scanner excerpt · scripts/mopidy.sh (reported line 80)May include surrounding context.

sh
uri="${1:-}"
    [ -n "$uri" ] || { echo "track uri required" >&2; exit 1; }
    rpc '{"jsonrpc":"2.0","id":1,"method":"core.tracklist.clear"}' >/dev/null
    jq -nc --arg uri "$uri" '{jsonrpc:"2.0",id:1,method:"core.tracklist.add",params:{uris:[$uri]}}' | curl -ksS -H 'Content-Type: application/json' -d @- "$MOPIDY_URL" >/dev/null
    rpc '{"jsonrpc":"2.0","id":1,"method":"core.playback.play"}'
    ;;
  pause)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This shell script sends user-supplied search queries and media URIs to the Mopidy server via HTTP requests, but the script provides no confirmation prompt, warning message, or explanatory comment about transmitting that data to a remote endpoint. Because these operations send user input over the network and some commands modify the remote queue, they meet the code-file criteria for missing disclosure.

Content

No source excerpt is available for this finding.