Back to skill

Security audit

AI Music Video

Security checks for vulnerabilities and agentic risk

Overview

The skill is meant to make AI music videos, but unsafe script argument handling could let crafted inputs run local code.

Review carefully before installing. Use it only in a constrained workspace with non-sensitive prompts and limited API keys, confirm each paid generation step, avoid passing untrusted text into script options, and consider fixing the python3 -c interpolation issues before running it with real credentials.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gen_visuals.sh:72
Finding

Arbitrary Python Code Execution Through Visual Generation Arguments

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/suno_music.sh:123
Finding

Arbitrary Python Code Execution Through Music and Persona Arguments

Content
View full analysis
"$PERSONA_BODY_FILE" ``` ### Technical Analysis Although prompts, styles, titles, and negative tags are initially placed in temporary files, se ...[truncated 2035 chars]
Remediation
View remediation
"$PERSONA_BODY_FILE" import json import sys task_id, audio_id, name, description, style = sys.argv[1:6] body = { "taskId": task_id, "audioId": audio_id, "name": name, "description": description, } if style: body["style"] = style json.dump(body, sys.stdout, ensure_ascii=False) PY ``` 4. Allowlist `MODEL` against the documented model identifiers. 5. Restrict `VOCAL_GENDER` to `m`, `f`, or an empty value. 6. Validate task, audio, and persona identifiers against the provider's documented identifier format. 7. Pass output directories through `sys.argv` and use standard path APIs. 8. Correct all related interpolation sites at lines `217-294`, `496-507`, and `528-539`. 9. Add negative tests using quotes, triple quotes, newline characters, and Python statement fragments in every user-controlled option. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/suno_music.sh:79
Finding

Dry-Run Mode Performs an Unexpected Authenticated Network Request

Content
View full analysis
/dev/null) CREDITS=$(echo "$CREDITS_RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',0))" 2>/dev/null || echo "unknown") if [[ "$CREDITS" == "unknown" || "$CREDITS" == "0" ]]; then CREDITS="N/A (credit API not available)" fi echo "💰 Credits: $CREDITS" # Cost estimate echo "" echo "📊 Cost Estimate" echo "━━━━━━━━━━━━━━━━━━━" echo " Model: $MODEL" echo " Mode: $([ "$CUSTOM_MODE" = true ] && echo 'Custom' || echo 'Simple')" echo " Instrumental: $INSTRUMENTAL" echo " Music Video: $MUSIC_VIDEO" if [[ -n "$PERSONA_ID" ]]; then echo " Persona: $PERSONA_ID" fi echo " Create Persona: $CREATE_PERSONA" echo " Est. credits: ~10 per generation (2 tracks)" echo " Credits: $CREDITS" echo "━━━━━━━━━━━━━━━━━━━" if [[ "$DRY_RUN" = true ]]; then echo "DRY_RUN: exiting without generation" exit 0 fi ``` ### Technical Analysis The script constructs an authorization header and calls the Suno credit endpoint before evaluating the `DRY_RUN` flag. Therefore, `--dry-run` is not network-free and transmits the bearer credential to `api.sunoapi.org`. This conflicts with the test-suite description that dry-run tests involve “no API calls, no cost.” Although `api.sunoapi.org` is the declared music provider and ordinary generation requires this network access, an authenticated request is not necessary to calculate the script's static cost estimate. This is not hidden exfiltration to an unrelated host, but it exceeds the minimum network activity needed for cost-only execution. ...[truncated 885 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (65)

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 · scripts/gen_visuals.sh (reported line 312)May include surrounding context.

sh
'width': 1536, 'height': 1024
}, ensure_ascii=False))
" > "$body_file"
  resp=$(curl -s -X POST "https://api.together.xyz/v1/images/generations" \
    -H "Authorization: Bearer $TOGETHER_API_KEY" \
    -H "Content-Type: application/json" \
    -d @"$body_file")

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

Although labeled as script fetching, the real issue is unvalidated remote content download from a URL supplied by an external service. This creates a trust-boundary problem where compromised API output could cause arbitrary remote retrieval and storage, which is more dangerous in an automation context that may run in CI or on hosts with network reachability.

Content

Scanner excerpt · scripts/gen_visuals.sh (reported line 329)May include surrounding context.

sh
if [[ -z "$url" || "$url" == ERROR* ]]; then
    echo "  ❌ Image gen failed" >&2; return 1
  fi
  curl -s -o "$outpath" "$url"
  echo "  ✅ $(basename "$outpath")"
}

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 · scripts/gen_visuals.sh (reported line 372)May include surrounding context.

sh
echo "  ❌ Video timeout" >&2; return 1
    fi
    local poll
    poll=$(curl -s "https://api.together.xyz/v2/videos/${video_id}" \
      -H "Authorization: Bearer $TOGETHER_API_KEY")
    status=$(echo "$poll" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))" 2>/dev/null)
    echo "    [${attempts}] $status"

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 · scripts/suno_music.sh (reported line 84)May include surrounding context.

sh
# Check credits (may not be supported by all sunoapi instances)
echo "🔍 Checking Suno credits..."
CREDITS_RESP=$(curl -s -H "$AUTH" "${API_BASE}/get-credits" 2>/dev/null)
CREDITS=$(echo "$CREDITS_RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',0))" 2>/dev/null || echo "unknown")
if [[ "$CREDITS" == "unknown" || "$CREDITS" == "0" ]]; then
  CREDITS="N/A (credit API not available)"

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 · scripts/suno_music.sh (reported line 161)May include surrounding context.

sh
echo ""
echo "🎵 Generating music..."
GEN_RESP=$(curl -s -X POST "${API_BASE}/generate" \
  -H "$AUTH" -H "$CT" \
  -d "$BODY")

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 · scripts/suno_music.sh (reported line 194)May include surrounding context.

sh
fi

  sleep 15
  POLL_RESP=$(curl -s -H "$AUTH" "${API_BASE}/generate/record-info?taskId=${TASK_ID}")
  STATUS=$(echo "$POLL_RESP" | python3 -c "
import sys, json
d = json.load(sys.stdin)

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

The lyrics response is embedded into a Python command via shell substitution inside a quoted -c string. Although the code tries to escape single quotes, adversarial API content can still make this fragile and may lead to command or parser breakage, turning untrusted remote data into part of executable interpreter input.

Content

Scanner excerpt · scripts/suno_music.sh (reported line 326)May include surrounding context.

sh
import json
print(json.dumps({'taskId': '$TASK_ID', 'audioId': '$AUDIO_ID'}))
")
    LYRICS_RESP=$(curl -s -X POST "${API_BASE}/generate/get-timestamped-lyrics" \
      -H "$AUTH" -H "$CT" \
      -d "$LYRICS_BODY")

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 · scripts/suno_music.sh (reported line 408)May include surrounding context.

sh
'callBackUrl': 'https://localhost/noop',
}))
")
    MV_RESP=$(curl -s -X POST "${API_BASE}/mp4/generate" \
      -H "$AUTH" -H "$CT" \
      -d "$MV_BODY")

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 · scripts/suno_music.sh (reported line 437)May include surrounding context.

sh
fi
        sleep 20

        MV_POLL=$(curl -s -H "$AUTH" "${API_BASE}/mp4/record-info?taskId=${MV_TASK_ID}")
        MV_STATUS=$(echo "$MV_POLL" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('successFlag','PENDING'))" 2>/dev/null || echo "PENDING")
        MV_VIDEO_URL=$(echo "$MV_POLL" | python3 -c "
import sys, json

External Script Fetching

High
Category
Supply Chain
Confidence
90% confidence
Finding

User-controlled values derived from TITLE, PROMPT, STYLE, PERSONA_NAME, and PERSONA_DESC are interpolated directly into a python3 -c string using triple-quoted literals. A crafted value containing quote sequences can break out of the Python string and inject arbitrary Python code, leading to local code execution under the script's privileges.

Content

Scanner excerpt · scripts/suno_music.sh (reported line 510)May include surrounding context.

sh
print(json.dumps(body, ensure_ascii=False))
" > "$PERSONA_BODY_FILE"

    PERSONA_RESP=$(curl -s -X POST "${API_BASE}/generate/generate-persona" \
      -H "$AUTH" -H "$CT" \
      -d @"$PERSONA_BODY_FILE")
    rm -f "$PERSONA_BODY_FILE"

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/conftest.py (reported line 17)May include surrounding context.

python
@pytest.fixture(scope="session")
def skill_env():
    """Environment with API keys from environment variables."""
    return os.environ.copy()


@pytest.fixture

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 138)May include surrounding context.

python
@pytest.fixture(scope="session")
def skill_env():
    """Environment with API keys from environment variables."""
    return os.environ.copy()


@pytest.fixture

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 304)May include surrounding context.

python
img_dir = os.path.join(work_dir, "images")
        os.makedirs(img_dir, exist_ok=True)
        for i in range(3):
            os.system(
                f'ffmpeg -y -f lavfi -i color=c=blue:s=1024x1024:d=1 '
                f'"{img_dir}/scene_{i:03d}.png" 2>/dev/null'
            )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 330)May include surrounding context.

python
img_dir = os.path.join(work_dir, "images")
        os.makedirs(img_dir, exist_ok=True)
        for i in range(3):
            os.system(
                f'ffmpeg -y -f lavfi -i color=c=blue:s=1024x1024:d=1 '
                f'"{img_dir}/scene_{i:03d}.png" 2>/dev/null'
            )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 358)May include surrounding context.

python
)
        img_dir = os.path.join(work_dir, "images")
        os.makedirs(img_dir, exist_ok=True)
        os.system(
            f'ffmpeg -y -f lavfi -i color=c=blue:s=1024x1024:d=1 '
            f'"{img_dir}/scene_000.png" 2>/dev/null'
        )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 296)May include surrounding context.

python
"""
        # Arrange: create synthetic audio (10s silence)
        audio_path = os.path.join(work_dir, "test_audio.mp3")
        os.system(
            f'ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=stereo -t 10 '
            f'-q:a 9 "{audio_path}" 2>/dev/null'
        )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 323)May include surrounding context.

python
"""
        # Arrange: create synthetic audio (10s silence)
        audio_path = os.path.join(work_dir, "test_audio.mp3")
        os.system(
            f'ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=stereo -t 10 '
            f'-q:a 9 "{audio_path}" 2>/dev/null'
        )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_dry_run.py (reported line 352)May include surrounding context.

python
"""
        # Arrange: create synthetic audio (10s silence)
        audio_path = os.path.join(work_dir, "test_audio.mp3")
        os.system(
            f'ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=stereo -t 10 '
            f'-q:a 9 "{audio_path}" 2>/dev/null'
        )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_integration.py (reported line 137)May include surrounding context.

python
"""
        # Arrange: create synthetic audio (10s silence)
        audio_path = os.path.join(work_dir, "test_audio.mp3")
        os.system(
            f'ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=stereo -t 10 '
            f'-q:a 9 "{audio_path}" 2>/dev/null'
        )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_integration.py (reported line 149)May include surrounding context.

python
colors = ["red", "green", "blue"]
        for i, color in enumerate(colors):
            img_path = os.path.join(img_dir, f"scene_{i:03d}.png")
            os.system(
                f'ffmpeg -y -f lavfi -i color=c={color}:s=1024x1024:d=1 '
                f'-frames:v 1 "{img_path}" 2>/dev/null'
            )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_integration.py (reported line 182)May include surrounding context.

python
"""Assemble slideshow with crossfade transitions."""
        # Arrange
        audio_path = os.path.join(work_dir, "audio.mp3")
        os.system(
            f'ffmpeg -y -f lavfi -i "sine=f=440:d=12" '
            f'-q:a 9 "{audio_path}" 2>/dev/null'
        )

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · tests/test_integration.py (reported line 191)May include surrounding context.

python
os.makedirs(img_dir, exist_ok=True)
        for i in range(3):
            img_path = os.path.join(img_dir, f"scene_{i:03d}.png")
            os.system(
                f'ffmpeg -y -f lavfi -i color=c=0x{i*80:02x}{i*40:02x}FF:s=1920x1080:d=1 '
                f'-frames:v 1 "{img_path}" 2>/dev/null'
            )

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documentation declares required binaries and environment variables and clearly instructs running shell scripts that perform network access, file reads/writes, and media assembly, but it does not declare an explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where an agent platform may expose broader capabilities than users expect, increasing the risk of unintended command execution, filesystem access, or outbound requests.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The Quick Start examples are broad natural-language triggers for expensive, networked generation actions and do not define clear activation boundaries, confirmation requirements, or exclusions. In an agent setting, ambiguous triggers can cause the skill to activate unintentionally, leading to unreviewed API usage, third-party data transmission, and unexpected spending.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation instructs users to provide API keys and describes callback behavior and third-party providers, but it lacks a prominent user-facing warning that prompts, lyrics, generated media, and callback metadata may be transmitted to external services. This can lead users to unknowingly send potentially sensitive creative content or metadata off-platform without informed consent.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.