Back to skill

Security audit

musicful music generator

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to generate music as advertised, but its configurable API endpoint can send the user’s Musicful API key and prompts to an arbitrary server if misconfigured or tampered with.

Review the .env file before use and keep MUSICFUL_BASE_URL set to the official HTTPS Musicful API host. Do not submit secrets, private lyrics, regulated data, or proprietary material unless you accept Musicful’s data handling terms. Treat any unexpected base URL change as a reason to rotate the Musicful API key.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/musicful_api.py:28
Finding

Unrestricted API Base URL Can Exfiltrate Credentials and User Content

Content
View full analysis
Dict[str, str]: key = api_key or DEFAULT_KEY if not key: raise RuntimeError( "MUSICFUL_API_KEY not configured. Edit: {} and set MUSICFUL_API_KEY=YOUR_KEY. " "Get/purchase a key at https://www.musicful.ai/api/authentication/interface-key/".format( _ENV_PATH ) ) return {"x-api-key": key, "Content-Type": "application/json"} def generate_lyrics(prompt: str, api_key: Optional[str] = None) -> Dict[str, Any]: url = f"{BASE_URL}/v1/lyrics" r = requests.post(url, json={"prompt": prompt}, headers=_headers(api_key), timeout=60) r.raise_for_status() j = r.json() return j.get("data", j) ``` ```python url = f"{BASE_URL}/v1/music/generate" data: Dict[str, Any] = { "action": action, "style": style, "mv": mv, "instrumental": instrumental, "gender": gender, } if prompt: data["prompt"] = prompt if action == "custom" and lyrics: data["lyrics"] = lyrics if title: data["title"] = title r = requests.post(url, json=data, headers=_headers(api_key), timeout=120) ``` ```python def query_tasks(task_ids: List[str], api_key: Optional[str] = None) -> List[Dict[str, Any]]: ids_str = ",".join(task_ids) url = f"{BASE_URL}/v1/music/tasks?ids={ids_str}" r = requests.get(url, headers=_headers(api_key), timeout=60) r.raise_for_status() return r.json().get("data", []) def generate_mp4(task_id: str, api_key: Optional[str] = None) -> Dict[str, Any]: url = f"{BASE_URL}/ ...[truncated 2956 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (34)

Tainted flow: 'url' from os.environ.get (line 137, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/musicful_api.py (reported line 48)May include surrounding context.

python
def generate_lyrics(prompt: str, api_key: Optional[str] = None) -> Dict[str, Any]:
    url = f"{BASE_URL}/v1/lyrics"
    r = requests.post(url, json={"prompt": prompt}, headers=_headers(api_key), timeout=60)
    r.raise_for_status()
    j = r.json()
    return j.get("data", j)

Tainted flow: 'url' from os.environ.get (line 137, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/musicful_api.py (reported line 80)May include surrounding context.

python
data["lyrics"] = lyrics
        if title:
            data["title"] = title
    r = requests.post(url, json=data, headers=_headers(api_key), timeout=120)
    r.raise_for_status()
    j = r.json()
    return j.get("data", {}).get("ids", []) or j.get("data", []) or j

Tainted flow: 'url' from os.environ.get (line 137, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/musicful_api.py (reported line 131)May include surrounding context.

python
def query_tasks(task_ids: List[str], api_key: Optional[str] = None) -> List[Dict[str, Any]]:
    ids_str = ",".join(task_ids)
    url = f"{BASE_URL}/v1/music/tasks?ids={ids_str}"
    r = requests.get(url, headers=_headers(api_key), timeout=60)
    r.raise_for_status()
    return r.json().get("data", [])

Tainted flow: 'url' from os.environ.get (line 137, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/musicful_api.py (reported line 138)May include surrounding context.

python
def generate_mp4(task_id: str, api_key: Optional[str] = None) -> Dict[str, Any]:
    url = f"{BASE_URL}/v3/music/generate-mp4"
    r = requests.post(url, json={"task_id": task_id}, headers=_headers(api_key), timeout=120)
    r.raise_for_status()
    return r.json()

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 (reported line 1)May include surrounding context.

text
# Copy to .env and fill your key
MUSICFUL_API_KEY=YOUR_API_KEY
MUSICFUL_BASE_URL=https://api.musicful.ai

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Requiring explicit CLI subcommands and supporting undeclared MP4 generation while advertising a simple auto-detected single-sentence flow is a trust-boundary problem. Users may invoke or authorize the skill under false assumptions about what it does, which is dangerous when the skill also uses network access and external services.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

Requiring explicit CLI subcommands and supporting undeclared MP4 generation while advertising a simple auto-detected single-sentence flow is a trust-boundary problem. Users may invoke or authorize the skill under false assumptions about what it does, which is dangerous when the skill also uses network access and external services.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

Requiring explicit CLI subcommands and supporting undeclared MP4 generation while advertising a simple auto-detected single-sentence flow is a trust-boundary problem. Users may invoke or authorize the skill under false assumptions about what it does, which is dangerous when the skill also uses network access and external services.

Content

No source excerpt is available for this finding.

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 · scripts/musicful_api.py (reported line 25)May include surrounding context.

python
# Resolve skill root dynamically (scripts/ -> skill root)
_SKILL_ROOT = Path(__file__).resolve().parents[1]
_ENV_PATH = _SKILL_ROOT / ".env"
# Load only the .env inside the actual skill folder (simple, unambiguous)
if _ENV_PATH.exists():
    load_dotenv(_ENV_PATH.as_posix())

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 132)May include surrounding context.

md
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI runner for Musicful API (reads .env in skill root):
Examples:
  # auto generate music
  python3 scripts/run_musicful.py auto --style "Happy songs" --mv v3.5

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 137)May include surrounding context.

md
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI runner for Musicful API (reads .env in skill root):
Examples:
  # auto generate music
  python3 scripts/run_musicful.py auto --style "Happy songs" --mv v3.5

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 37)May include surrounding context.

md
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI runner for Musicful API (reads .env in skill root):
Examples:
  # auto generate music
  python3 scripts/run_musicful.py auto --style "Happy songs" --mv v3.5

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 40)May include surrounding context.

md
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI runner for Musicful API (reads .env in skill root):
Examples:
  # auto generate music
  python3 scripts/run_musicful.py auto --style "Happy songs" --mv v3.5

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 · scripts/musicful_api.py (reported line 26)May include surrounding context.

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI runner for Musicful API (reads .env in skill root):
Examples:
  # auto generate music
  python3 scripts/run_musicful.py auto --style "Happy songs" --mv v3.5

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 · scripts/run_musicful.py (reported line 4)May include surrounding context.

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI runner for Musicful API (reads .env in skill root):
Examples:
  # auto generate music
  python3 scripts/run_musicful.py auto --style "Happy songs" --mv v3.5

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README clearly describes sending user prompts and task-status queries to Musicful API endpoints, but it does not prominently disclose that user-provided text and related metadata will be transmitted to a third-party service. This creates a privacy and data-handling risk because users may unknowingly submit sensitive prompts, lyrics, or identifiers to an external provider.

Content

No source excerpt is available for this finding.

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 · README.md (reported line 73)May include surrounding context.

Quick Examples

  • Generate a vocal song
text
/music_generator "Write an emotional pop song about distance and memory"
  • Generate background music (BGM)
text

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill explicitly instructs access to environment secrets and outbound network use, but it declares no tool scope or permission boundary. That mismatch can cause the platform or user to approve a skill without understanding it will read local configuration and send data externally, weakening least-privilege controls and auditability.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill omits a clear warning that user prompts, lyrics, and generated content are sent to a third-party music-generation API. This creates a privacy and data-governance risk because users may submit sensitive or copyrighted material without informed consent about external transmission and retention.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description says the system generates music or lyrics from a single sentence and automatically polls until it returns preview and final audio. However, the manifest actually exposes six separate commands, including explicit task-status querying and MP4 generation, which means the skill behavior is broader and less automatic than described.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill sends user prompts and potentially full lyrics to an external third-party music service using an API key, yet the manifest does not warn users that their content leaves the local environment. This can cause unintentional disclosure of sensitive or proprietary text, and the auto-polling behavior increases the amount of remote interaction without clear consent or transparency.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description is limited to generating AI music or lyrics and returning preview/final downloadable audio. A separate command to generate MP4 output adds a media-conversion/video capability not disclosed in that purpose statement.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

User prompts are transmitted to a third-party API, but the code provides no in-band notice, consent check, or minimization of potentially sensitive text. In an agent skill context, users may assume local processing, so this can create an unintended privacy and data-handling risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/musicful_api.py (reported line 48)May include surrounding context.

python
def generate_lyrics(prompt: str, api_key: Optional[str] = None) -> Dict[str, Any]:
    url = f"{BASE_URL}/v1/lyrics"
    r = requests.post(url, json={"prompt": prompt}, headers=_headers(api_key), timeout=60)
    r.raise_for_status()
    j = r.json()
    return j.get("data", j)

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/musicful_api.py (reported line 80)May include surrounding context.

python
def generate_lyrics(prompt: str, api_key: Optional[str] = None) -> Dict[str, Any]:
    url = f"{BASE_URL}/v1/lyrics"
    r = requests.post(url, json={"prompt": prompt}, headers=_headers(api_key), timeout=60)
    r.raise_for_status()
    j = r.json()
    return j.get("data", j)

Static analysis

No suspicious patterns detected.