Back to skill

Security audit

Spotplay

Security checks for vulnerabilities and agentic risk

Overview

This Spotify playback skill is mostly purpose-aligned, but it uses overbroad routing instructions and can send ambiguously named credentials to Spotify without clear user control.

Review before installing. Use it only if you want a macOS Spotify.app controller, and avoid running it in environments where generic CLIENT_ID or CLIENT_SECRET variables contain credentials for other services. Prefer explicitly scoped SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET values, and be aware that the skill documentation tries to steer the agent to use this skill over other Spotify playback options.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:6
Finding

Forced Skill Selection and Suppression of Competing Skills

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
spotplay.py:20
Finding

Generic Environment Variables May Disclose Unrelated Credentials to Spotify

Content
View full analysis
str: basic = base64.b64encode(f"{cid}:{csec}".encode("utf-8")).decode("ascii") j = http_post( "https://accounts.spotify.com/api/token", {"Authorization": f"Basic {basic}"}, {"grant_type": "client_credentials"}, ) ``` ### Technical Analysis Using HTTP Basic authentication and Base64 encoding is expected for Spotify's client-credentials token flow. Base64 is not encryption, but the request is sent to Spotify's official HTTPS endpoint, so the encoding is not evidence of a covert channel by itself. The vulnerability arises from the fallback to the generic environment variables `CLIENT_ID` and `CLIENT_SECRET`. These names are not scoped to Spotify and may contain credentials for an unrelated application or service. If Spotify-specific variables are absent, the code treats the generic values as Spotify credentials and places them in an outbound Authorization header. The fallback exceeds least privilege because the Skill only needs credentials explicitly designated for Spotify. It should not inspect or transmit ambiguously scoped secre ...[truncated 1253 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (5)

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill declares that it must be used for essentially any user intent related to playing music and explicitly instructs the agent not to choose alternative Spotify-related skills. This creates an overly broad routing rule that can override more appropriate tools, increase unintended invocation, and cause actions to be taken on the user's device without sufficient disambiguation or consent.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · spotplay.py (reported line 15)May include surrounding context.

python
CFG = os.path.expanduser("~/.shpotify.cfg")

def run(cmd: str) -> str:
    p = subprocess.run(cmd, shell=True, text=True, capture_output=True)
    out = (p.stdout or "").strip()
    err = (p.stderr or "").strip()
    if p.returncode != 0:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
72% confidence
Finding

The entire skill documentation is written in Traditional Chinese and does not indicate any option for alternative language or locale handling. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless clearly documented as region-specific or optional.

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 · spotplay.py (reported line 15)May include surrounding context.

python
CFG = os.path.expanduser("~/.shpotify.cfg")

def run(cmd: str) -> str:
    p = subprocess.run(cmd, shell=True, text=True, capture_output=True)
    out = (p.stdout or "").strip()
    err = (p.stderr or "").strip()
    if p.returncode != 0:

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · spotplay.py (reported line 67)May include surrounding context.

python
def search_track_uri(query: str, token: str) -> tuple[str, str]:
    q = urllib.parse.quote(query)
    url = f"https://api.spotify.com/v1/search?q={q}&type=track&limit=1"
    j = http_get(url, {"Authorization": f"Bearer {token}"})
    items = (((j.get("tracks") or {}).get("items")) or [])
    if not items: