Back to skill

Security audit

MusicPlaylistGen

Security checks for vulnerabilities and agentic risk

Overview

PlaylistGen appears to do what it claims, but its unauthenticated server can expose your music library and use your AI API account if reachable on a network.

Review before installing. Use this only on a trusted machine, bind it to localhost or firewall the port, do not expose it to LAN/public networks without authentication, protect .env and API keys, and expect music metadata and prompts to be sent to Anthropic or MiniMax. Avoid running start.sh with elevated privileges, and check for port conflicts manually because the script can terminate another process on the chosen port.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
playlist_server.py:1375
Finding

Unauthenticated Network Exposure of the Music Library and Paid LLM Operations

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
playlist_server.py:581
Finding

Absolute Filesystem Paths Exposed Through Unauthenticated API Responses

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
playlist_server.py:1216
Finding

Stored and DOM-Based Cross-Site Scripting Through Unescaped Music Metadata and Playlist Titles

Content
View full analysis
'
' + '' + s.title + '
' + s.artist + ' - ' + s.album + '
' ).join(''); } ``` ```javascript const _savedData = ''' + (json.dumps(saved) if saved else 'null') + '''; ``` ```javascript function renderPlaylist(label) { const container = document.getElementById('playlist'); const header = '

Playlist: ' + label + ' (' + playlist.length + ' songs)' + '🔀 Shuffle' + (shuffled ? ' ON' : '') + '

'; const items = playlist.map((s, i) => '
' + '' + (i+1) + '. ' + s.title + '' + '
' + s.artist + ' - ' + s.album + '
' ).join(''); container.innerHTML = header + items; } ``` ### Technical Analysis Values derived from audio tags, filenames, database records, and API-supplied playlist titles are concatenated into HTML strings and assigned to `innerHTML`. No HTML escaping or sanitization is performed. An attacker-controlled title, artist, album, URL, or playlist title can therefore introduce elements or event handlers. The search result's inline `onclick` construction also places an untrusted URL inside a JavaScript string embedded in HTML ...[truncated 2223 chars]
Remediation
View remediation
... ``` Escape at least `<`, `>`, `&`, and script-closing sequences before embedding, then parse the element's `textContent`. 6. Validate playlist titles for type and maximum length on the server. 7. Add a restrictive Content Security Policy that disallows inline scripts and event handlers, for example through nonces or separate static JavaScript files. 8. Add automated tests using metadata values containing quotes, HTML elements, event handlers, and ``. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
start.sh:19
Finding

Startup Script Terminates Unrelated Processes Listening on the Configured Port

Content
View full analysis
/dev/null || true sleep 1 ``` ### Technical Analysis `fuser -k /tcp` terminates processes using the selected TCP port. The command does not verify that the process is a previous PlaylistGen instance, was created by this script, or is safe to stop. The port value is configurable through `.env` or the inherited environment. Consequently, an incorrect or attacker-influenced value can cause the script to terminate an unrelated service. If the script is run with elevated privileges, the scope expands to processes owned by other users. Killing existing listeners is not necessary to start PlaylistGen safely. A least-privilege implementation should report the conflict and stop, or terminate only a previously recorded PlaylistGen PID after verifying its identity. ### Attack Path 1. A legitimate service is already listening on a TCP port. 2. The `PORT` environment variable or `.env` file is configured to that port. 3. The user runs `bash start.sh`. 4. `fuser -k` terminates the existing listener. 5. PlaylistGen attempts to replace the terminated service. 6. The unrelated workload becomes unavailable and may lose in-memory state or active connections. ### Impact Assessment The immediate impact is local denial of service against any process the current user is authorized to signal. Possible consequences include: - Termination of development servers, databases, proxies, or administrative tools. - Loss of active connections and unsaved in-memory work. - Unexpected replacement of an unrelated network service. - Broader disruption if the startup script is run with elevated privileges. The command does not itself escalate privileges, but it crosses application ownership bo ...[truncated 84 chars]
Remediation
View remediation
/dev/null 2>&1; then echo "Port $PORT is already in use; refusing to terminate the existing service." exit 1 fi ``` 2. Record the PlaylistGen PID in a dedicated PID file after startup. 3. For restart operations: - Read the PID file. - Verify that the PID is owned by the current user. - Verify that its executable and command line correspond to `playlist_server.py`. - Send `TERM`, wait for graceful shutdown, and use `KILL` only as an explicit last resort. 4. Validate `PORT` as an integer in the range 1–65535. 5. Never recommend running `start.sh` with `sudo`. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:41
Finding

Unpinned Third-Party Dependencies Installed Without Integrity Verification

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (42)

Credential Access

High
Category
Privilege Escalation
Confidence
78% confidence
Finding

The README instructs users to source .env before running the indexer, which imports secrets directly into the shell environment. In agent-assisted or multi-user environments, environment variables can be exposed through shell history, subprocess inheritance, debug output, crash reports, or accidental logging, making credential leakage more plausible than simply storing them in a file.

Content

Scanner excerpt · README.md (reported line 113)May include surrounding context.

This scans your music directory and enriches each song with LLM-generated tags. Runs once; safe to re-run (skips already-indexed songs).

bash
source .env
python3 smart_indexer.py --path "$MUSIC_DIR" --llm haiku --key "$ANTHROPIC_API_KEY" --db "$DB_PATH" --workers 1

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

Scanner excerpt · SKILL.md (reported line 124)May include surrounding context.

Verify it's up:

bash
curl -s http://localhost:5678/api/stats | python3 -m json.tool | head -5

Tell the user: "PlaylistGen is running at http://localhost:5678 — open it in a browser to search your library."

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 104)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 105)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 53)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 58)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 90)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 152)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · env.sample.md (reported line 2)May include surrounding context.

md
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · playlist_server.py (reported line 19)May include surrounding context.

python
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · smart_indexer.py (reported line 33)May include surrounding context.

python
# PlaylistGen Environment Variables
# Copy this file to .env and fill in your values

# ── Required ────────────────────────────────────────────────────────────────

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · playlist_server.py (reported line 20)May include surrounding context.

python
def _load_dotenv():
    """Load .env from the script's directory into os.environ (no-op if missing)."""
    env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env')
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · smart_indexer.py (reported line 34)May include surrounding context.

python
def _load_dotenv():
    """Load .env from the script's directory into os.environ (no-op if missing)."""
    env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '.env')
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · playlist_server.py (reported line 243)May include surrounding context.

python
print(f"MUSIC_RULES.md not found at {MUSIC_RULES_PATH} — using built-in defaults")
    except Exception as e:
        print(f"Warning: could not load MUSIC_RULES.md: {e}")
    return rules

# ── Catalog vocabulary (pre-built at startup, refreshable) ────────────────────
_catalog_vocab: dict = {}

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The script sources .env as shell code using source .env, which does more than load credentials: it executes any commands embedded in that file in the current shell context. If an attacker can modify .env, this becomes arbitrary command execution and can also expose sensitive secrets loaded into the environment.

Content

Scanner excerpt · start.sh (reported line 9)May include surrounding context.

sh
cd "$SCRIPT_DIR"

# Load environment
if [ -f .env ]; then
    set -a; source .env; set +a
else
    echo "Warning: .env not found. Using defaults or existing environment."

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

This finding points to the same risky behavior: loading .env through shell source executes file contents rather than merely reading configuration. In the context of a startup script, that means a tampered .env can run arbitrary commands before the server starts and inherit access to the user's environment and filesystem.

Content

Scanner excerpt · start.sh (reported line 12)May include surrounding context.

sh
if [ -f .env ]; then
    set -a; source .env; set +a
else
    echo "Warning: .env not found. Using defaults or existing environment."
fi

# Use venv if present

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 39)May include surrounding context.

  1. Do they have an Anthropic API key, MiniMax API key, or both? (Anthropic Haiku preferred)
  2. What IP/port should playlist links use? (default http://localhost:5678 works for local use; set MUSIC_SERVER_URL to a LAN/Tailscale IP if they want links to work on other devices)

Step 2 — Create the virtual environment

bash
cd ~/.openclaw/skills/playlistgen

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README.md (reported line 95)May include surrounding context.

Also check that ffprobe is available:

bash
ffprobe -version
# If missing: sudo apt install ffmpeg   (Linux) or brew install ffmpeg (macOS)

Step 3 — Create .env

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 50)May include surrounding context.

Also check that ffprobe is available:

bash
ffprobe -version
# If missing: sudo apt install ffmpeg   (Linux) or brew install ffmpeg (macOS)

Step 3 — Create .env

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This music server quietly includes external LLM integrations and loads API credentials from environment variables, expanding the trust boundary beyond local playlist serving. In this skill context, that is security-relevant because user prompts and library metadata can be sent to third-party services, creating an unexpected data exfiltration path and increasing attack surface.

Content

No source excerpt is available for this finding.

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

python
import openai  # type: ignore
    _minimax_client = openai.OpenAI(
        api_key=os.environ.get("MINIMAX_API_KEY", ""),
        base_url="https://api.minimax.io/v1"
    )
    HAS_MINIMAX = bool(os.environ.get("MINIMAX_API_KEY", ""))
except Exception:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

User-supplied prompts are transmitted to Anthropic or MiniMax without clear disclosure or consent. In this application context, prompts may contain private listening preferences or other free-form text, and the unexpected external transmission creates a real privacy and data-governance risk.

Content

No source excerpt is available for this finding.

Tainted flow: 'vocab_path' from os.environ.get (line 340, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · playlist_server.py (reported line 341)May include surrounding context.

python
conn.close()

    vocab_path = os.path.join(os.path.dirname(DB_PATH), "music_catalog_vocab.json")
    with open(vocab_path, 'w', encoding='utf-8') as f:
        json.dump(out, f, indent=2, ensure_ascii=False)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
92% confidence
Finding

The ffmpeg subprocess is invoked on a path derived from an HTTP request via translate_path(), allowing remote users to trigger server-side processing of arbitrary reachable files. Although shell injection is avoided by using an argument list, this still exposes the service to resource-exhaustion and potentially ffmpeg parser exploitation on attacker-chosen media inputs, which is significant in a network-facing threaded server.

Content

Scanner excerpt · playlist_server.py (reported line 424)May include surrounding context.

python
self.send_header('Content-Type', 'audio/mpeg')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        proc = subprocess.Popen(
            ['ffmpeg', '-i', path, '-f', 'mp3', '-b:a', '192k', '-vn', 'pipe:1'],
            stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
        )

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · playlist_server.py (reported line 925)May include surrounding context.

python
- HARD LIMIT: Never select more than 2 tracks from the same artist
- Maintain genre consistency (or subgenre consistency if the playlist targets a specific subgenre)
- Maximize artist diversity — avoid clustering the same artist back-to-back                                                             
- If the prompt implies a specific era (decade or period), prefer songs whose year falls in that range; otherwise spread across eras for variety                                                                                                                                
- If the prompt implies a specific region or culture, prefer songs from that region; otherwise spread across regions for variety        
- If the prompt implies a popularity level (e.g. "obscure", "hits"), apply it as a strong preference; otherwise mix mainstream and niche tracks for variety                                                                                                                     
- Order for smooth energy and mood transitions"""

Static analysis

No suspicious patterns detected.