T09 · Insecure Skill Coding Practices
- Location
scripts/spotify-queue.sh:108- Finding
Arbitrary Python Code Execution Through a Crafted Spotify URI
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly transparent about identifying songs and using Spotify, but its Spotify queue helper contains a crafted-URI code execution flaw and its OAuth token handling is too exposed.
Review this skill before installing. Do not use the Spotify queue feature until the URI handling is fixed, and prefer a localhost OAuth callback with state validation and token files created with mode 600. Only send audio clips you are comfortable uploading to AudD, and treat the Spotify credentials, OAuth tokens, and music log as private data.
scripts/spotify-queue.sh:108Arbitrary Python Code Execution Through a Crafted Spotify URI
scripts/spotify-auth.py:27Spotify OAuth Flow Does Not Validate a State Parameter
scripts/spotify-auth.py:104Spotify OAuth Callback Server Listens on All Network Interfaces
scripts/spotify-auth.py:72OAuth Tokens Are Initially Written Without Enforcing Restrictive Permissions
scripts/spotify-queue.sh:46Token Refresh Can Replace a Protected Token File With a More Permissive File
scripts/spotify-queue.sh:115Unescaped Values Are Concatenated Into JSON Responses
The core declared purpose of song identification using the AudD API is accurately represented by the code. However, several material parts of the description are not implemented in this code chunk: there is no Spotify queueing logic, no trigger handling, and no recall functionality that reads a music log. The script only performs audio-file submission to AudD and returns normalized results. Reading the API key from a local config file is a supporting implementation detail rather than a problematic mismatch. Because the description claims broader functionality than the code actually provides, this chunk does not fully match the declared behavior.
This code chunk’s primary purpose is Spotify authentication setup, not song recognition. While Spotify integration could be a supporting part of a larger skill, the supplied description centers on identifying songs from audio and recalling recognized tracks. None of that behavior appears here: there is no audio ingestion, no AudD API usage, no command/intent handling, and no music-log access. Instead, the code exposes an undeclared capability—running an HTTP server to complete OAuth and persisting Spotify tokens—which is materially different from the declared purpose.
The declared purpose centers on song recognition from audio and recall of previously identified songs, with Spotify queueing only as an optional downstream action. The actual code does not analyze audio, identify songs, call AudD, log music history, or implement any of the described triggers/query handling. Instead, it is solely a Spotify queue/status helper that manages OAuth tokens and interacts with Spotify playback endpoints. This is a materially different primary purpose from the declared description.
The skill is explicitly designed to access locally stored API keys, OAuth tokens, and client credentials. Credential access is expected for functionality, but in an agent context it is still sensitive because compromise or overbroad tool access could expose third-party account secrets and enable unauthorized Spotify actions.
|---|---|---|---|
| AudD API key | `~/.config/audd/api_key` | Yes | Song identification |
| Spotify OAuth tokens | `~/.config/spotify/tokens.json` | No (optional) | Queue to Spotify |
| Spotify app credentials | `~/.config/spotify/credentials.json` | No (optional) | Token refresh |
**Security notes:**
- All credential files should be restricted: `chmod 600`.
The documentation instructs users to place Spotify client secrets in a plaintext JSON file under the home directory. Even with 0600 permissions, storing reusable app secrets on disk increases the blast radius if the agent, host account, or filesystem is compromised.
mkdir -p ~/.config/spotify
cat > ~/.config/spotify/credentials.json << 'EOF'
{"client_id": "...", "client_secret": "...", "redirect_uri": "https://your-host/callback"}
EOF
chmod 600 ~/.config/spotify/credentials.json
This finding again reflects on-disk handling of Spotify client credentials, which are sensitive and reusable. In combination with shell and file-write capabilities, plaintext credential files can be copied, overwritten, or misused by other components on the same host.
cat > ~/.config/spotify/credentials.json << 'EOF' {"client_id": "...", "client_secret": "...", "redirect_uri": "https://your-host/callback"} EOF chmod 600 ~/.config/spotify/credentials.json
4. Run the auth flow: `python3 scripts/spotify-auth.py`
5. Open the printed URL in a browser, authorize, tokens save automatically
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# spotify-queue.sh status
TOKEN_FILE="$HOME/.config/spotify/tokens.json"
CREDS_FILE="$HOME/.config/spotify/credentials.json"
if [[ ! -f "$TOKEN_FILE" ]]; then
echo '{"status":"error","message":"not authenticated. run spotify-auth.py first"}'
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# spotify-queue.sh status
TOKEN_FILE="$HOME/.config/spotify/tokens.json"
CREDS_FILE="$HOME/.config/spotify/credentials.json"
if [[ ! -f "$TOKEN_FILE" ]]; then
echo '{"status":"error","message":"not authenticated. run spotify-auth.py first"}'
The skill declares shell, network, and file-write behaviors but provides no explicit permission or allowed-tools scope. In an agent environment, missing tool scoping increases the chance the skill can invoke broader capabilities than intended, especially since it handles local files, external APIs, and persistent logging.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
| Spotify app credentials | `~/.config/spotify/credentials.json` | No (optional) | Token refresh |
**Security notes:**
- All credential files should be restricted: `chmod 600`.
- This skill does not read, store, or access any platform tokens (Telegram, Discord, etc.). Audio file download from messaging platforms is handled by the host agent, not by this skill.
## Trigger
Broad trigger phrases like 'what was that song' or 'what did I shazam' can overlap with ordinary conversation and cause the skill to activate unexpectedly. In a chat agent, overbroad activation can expose prior music-log contents or trigger file reads/network actions without clear user intent.
The skill persists an AudD API key and logs identified songs across sessions. Persistence is functionally necessary, but it increases privacy and abuse risk because both credentials and user activity history remain available for later access, including potentially unintended recall queries.
mkdir -p ~/.config/audd
echo "YOUR_KEY" > ~/.config/audd/api_key
chmod 600 ~/.config/audd/api_key
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
mkdir -p ~/.config/audd
echo "YOUR_KEY" > ~/.config/audd/api_key
chmod 600 ~/.config/audd/api_key
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
mkdir -p ~/.config/audd
echo "YOUR_KEY" > ~/.config/audd/api_key
chmod 600 ~/.config/audd/api_key
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
mkdir -p ~/.config/audd
echo "YOUR_KEY" > ~/.config/audd/api_key
chmod 600 ~/.config/audd/api_key
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# AudD API Reference (Summary)
## Endpoint
- POST https://api.audd.io/
## Parameters (multipart/form-data)
- `file`: Audio file to identify (OGG/Opus accepted)
This script makes an outbound network request to api.audd.io and sends user-supplied audio plus an authentication token. While external transmission is expected for song identification, it is still security-relevant because it transfers potentially sensitive voice/audio content outside the local trust boundary; the skill context increases concern because voice messages may contain more than just music.
exit 2
fi
response="$(curl -sS -F "file=@${audio_path}" -F "api_token=${api_key}" -F "return=spotify" https://api.audd.io/ || true)"
if [[ -z "$response" ]]; then
echo '{"status":"error","message":"empty api response"}'
The script uploads the provided audio file and the AudD API token to a third-party service, but the script itself contains no mechanism for user disclosure, consent, or minimization of shared data. In a skill that may trigger on voice messages, this can expose user audio content to an external processor unexpectedly, creating privacy and compliance risk even if the behavior is core to the feature.
The manifest describes identifying songs via AudD and optionally queueing them to Spotify, but this file implements a separate OAuth callback server that obtains Spotify access/refresh tokens and writes them to disk. While Spotify integration is mentioned, this operational behavior is significantly broader than simple song identification and is not reflected in the manifest description for this script's role.
OAuth tokens are written to disk automatically with no prior notice, consent prompt, or file-permission hardening. If the host is multi-user, backed up insecurely, or compromised later, the stored refresh token can provide persistent access to the user's Spotify account within the granted scopes.
The callback server listens on 0.0.0.0, exposing the OAuth callback handler on all network interfaces instead of only localhost. On a shared network or if port forwarding/Tailscale Serve is involved, another host may be able to send spoofed requests or race the callback flow, increasing the risk of unauthorized token handling or token overwrite.
This shell script reads sensitive authentication material from local credential and token files and later updates the token file, but it provides no user-facing warning, confirmation, or explanatory disclosure about handling secrets. For code files, accessing credentials and writing authentication data should have some visible disclosure unless clearly communicated elsewhere in the skill description, which is not present in this file.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Try a request; if 401, refresh token
try_refresh() {
local response
response=$(curl -sS -X POST "https://accounts.spotify.com/api/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&refresh_token=${refresh_token}&client_id=${client_id}&client_secret=${client_secret}")
The token refresh request sends the refresh token, client ID, and client secret to Spotify over HTTP, and the API helper also transmits the bearer access token in subsequent requests. Although these network calls are part of the script's function, this file does not include a visible warning, print, or explanatory note that authentication data is being sent to external Spotify endpoints.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
local http_code body
if [[ -n "$data" ]]; then
response=$(curl -sS -w "\n%{http_code}" -X "$method" "$url" \
-H "Authorization: Bearer ${access_token}" \
-H "Content-Type: application/json" \
-d "$data")
No suspicious patterns detected.