Back to skill

Security audit

Sun to Spotify

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned, but it recommends unsafe installation and includes sensitive authentication flows that users should review before installing.

Review this skill before installing. Prefer an isolated, exact-version CLI install through uv tool or pipx instead of curl-to-bash, perform browser login yourself, avoid pasting passwords or full tokens into agent chats or logs, and confirm the Sun API host and Spotify publishing target before allowing uploads or token creation.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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 (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:33
Finding
Mutable Remote Installer Is Executed Directly Through Bash<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:33` and `cli-usage.md:14` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: High ### Vulnerable Code ```bash curl -fsSL https://sunapp-ai.github.io/sun-to-spotify/install.sh | bash ``` ### Technical Analysis The recommended installation command downloads a mutable remote shell script and passes it directly to Bash. The content is neither displayed nor stored for inspection before execution, and the documentation does not require a checksum, signature, immutable commit reference, or other integrity verification. TLS protects the connection in transit but does not protect against compromise of the hosting account, repository, publication workflow, or upstream domain. Because the effective script can change after the Skill has been reviewed, the command creates a remote code-execution channel controlled by the current content of `install.sh`. This behavior is not the minimum privilege necessary to install the CLI. The documentation already presents package-manager alternatives that can be isolated and pinned. ### Attack Path 1. An attacker compromises the GitHub repository, GitHub Pages deployment, maintainer account, or publication workflow serving `install.sh`. 2. The attacker modifies the remote installer to include arbitrary shell commands. 3. A user or agent follows the Skill's recommended installation instructions. 4. `curl` retrieves the modified content and streams it directly into Bash. 5. The payload executes with all filesystem, network, process, and credential access available to the invoking account. ### Impact Assessment Successful exploitation provides arbitrary command execution with the privileges of the user running the installer. The payload could read accessible credentials, including Sun or Spotify authentication material, modify shell configuration, alter files, install additional software, or exfiltrate user data. The command does not reque ...[truncated 242 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the direct `curl | bash` pipeline from all documentation. 2. Prefer an isolated package-manager installation using an exact, audited version. 3. If a shell installer must remain available: - Publish it under an immutable release URL. - Download it to a local file first. - Publish and verify a SHA-256 checksum or cryptographic signature. - Require review of the downloaded script before execution. - Execute it as an unprivileged user. 4. Protect the release workflow with branch protection, mandatory review, signed releases, and tightly scoped deployment credentials. 5. Keep the installer optional rather than describing it as the recommended method. Example hardened workflow: ```bash curl -fSLo install.sh "https://example.invalid/releases/v0.2.1/install.sh" echo "<trusted-sha256> install.sh" | sha256sum --check - less install.sh bash install.sh ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:139
Finding
User-Controlled Prompt Is Demonstrated Through Shell String Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:139-150` **Vulnerability Type**: Shell command-injection risk **Risk Level**: High ### Vulnerable Code ```bash sun audio create \ --prompt "<the user's prompt>" \ --duration-minutes <N> \ --json ``` The persistence example repeats the same unsafe construction pattern: ```bash JOB_ID=$(sun audio create --prompt "..." --duration-minutes 30 --json | jq -r .job_id) echo "$JOB_ID" > "$OUT_DIR/.sun-job-id" ``` ### Technical Analysis The Skill states that the audio prompt comes from the user, then demonstrates inserting that value into a double-quoted shell command. If an agent constructs a command string by replacing the placeholder with the prompt, embedded quotation marks, command substitutions, backticks, or shell operators may terminate the intended argument and introduce additional shell syntax. Quoting a placeholder in documentation is not equivalent to safely passing a runtime value. The risk arises when untrusted content is interpolated into a command string before the shell parses it. The document mentions using `--input` or stdin for long prompts, but it does not require that safer approach for all untrusted prompts. ### Attack Path 1. A user supplies a prompt containing shell syntax, such as a closing quote followed by command substitution or another command. 2. An agent substitutes that prompt text into the documented `--prompt "..."` template. 3. The resulting command is sent to a shell rather than invoked through a structured argument array. 4. The shell parses the injected syntax separately from the intended prompt argument. 5. The injected command executes under the agent's operating-system account. Exploitation depends on the execution environment performing textual shell interpolation. A structured process API that passes an argument array without a shell would not be vulnerable to this path. ### Impact Assessment Successful exploitation could execute arbitrary commands ...[truncated 459 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require all user-controlled prompts to be passed through stdin or a securely created input file. 2. Do not construct shell source by substituting user text into command templates. 3. Where supported, invoke the executable using a structured argument array with `shell=False`. 4. If a temporary input file is necessary: - Create it with restrictive permissions. - Avoid predictable filenames. - Delete it after use. 5. Update every example to use the same safe pattern. Safer shell example: ```bash printf '%s' "$USER_PROMPT" | sun audio create \ --duration-minutes "$DURATION" \ --json ``` Safer process invocation conceptually: ```python subprocess.run( ["sun", "audio", "create", "--prompt", user_prompt, "--duration-minutes", str(duration), "--json"], shell=False, check=True, ) ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
http-api.md:5
Finding
Dynamic Authentication Discovery Can Redirect User Credentials<![CDATA[ ## Vulnerability Details **File Location**: `http-api.md:5-39` **Vulnerability Type**: Unsafe credential destination discovery **Risk Level**: High ### Vulnerable Code ```bash BASE="https://<your-sun-api-host>" ``` ```bash CFG=$(curl -s "$BASE/v1/public/auth-config") SUPABASE_URL=$(echo "$CFG" | jq -r .supabase_url) SUPABASE_ANON_KEY=$(echo "$CFG" | jq -r .supabase_anon_key) ``` ```bash JWT=$(curl -sX POST "$SUPABASE_URL/auth/v1/token?grant_type=password" \ -H "apikey: $SUPABASE_ANON_KEY" \ -H "Content-Type: application/json" \ -d '{"email":"alice@example.com","password":"..."}' \ | jq -r .access_token) ``` ### Technical Analysis The HTTP fallback permits a configurable `BASE`, obtains `supabase_url` from that server, and then sends an email address and password to the returned URL. The documented flow does not enforce an allowlist of trusted Sun and Supabase origins, pin the expected production host, or require explicit verification of the discovered destination before credentials are transmitted. The Supabase anonymous key is intended to be public and is not itself a secret. The security concern is that an untrusted or misconfigured `auth-config` response controls the destination receiving the user's password. This fallback also handles a reusable account password directly, which carries greater authority than the scoped personal API token needed for ordinary audio-generation operations. It therefore exceeds the minimum credential exposure necessary when browser authentication or a pre-provisioned API token is available. ### Attack Path 1. An attacker persuades a user or agent to set `BASE` to an attacker-controlled or compromised API host, or compromises the configured host. 2. The malicious `/v1/public/auth-config` response supplies an attacker-controlled `supabase_url`. 3. The documented commands accept the response without validating its origin. 4. The password-grant request sends the user's email and password to the attacker-co ...[truncated 620 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not ask an agent to handle or transmit the user's account password. 2. Prefer the documented interactive browser login and require the user to perform it directly. 3. For headless operation, accept only a user-provisioned, scoped `SUN_TOKEN` from a secret manager. 4. If password-grant support is unavoidable: - Pin the approved production API hostname. - Allowlist the exact expected Supabase origin. - Require HTTPS with normal certificate validation. - Reject redirects and unexpected schemes, ports, or hosts. - Display the credential destination and require explicit user confirmation. - Avoid placing passwords directly in shell source or command history. 5. Clearly separate local-development examples from production authentication instructions and warn that untrusted `BASE` values must never receive credentials. ]]>

T08 · Insecure Dependencies

Warning
Location
cli-usage.md:19
Finding
CLI Installation Allows Unreviewed Future Dependency Releases<![CDATA[ ## Vulnerability Details **File Location**: `cli-usage.md:19-32` and `SKILL.md:36-42` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash uv tool install 'sun-cli>=0.2.1' ``` ```bash pip install 'sun-cli>=0.2.1' # or, isolated: pipx install 'sun-cli>=0.2.1' ``` The primary Skill document contains equivalent commands: ```bash uv tool install 'sun-cli>=0.2.1' pipx install 'sun-cli>=0.2.1' pip install 'sun-cli>=0.2.1' ``` ### Technical Analysis The version constraint specifies only a minimum version. Package resolvers may therefore select any newer release available at installation time, including a version published after the Skill was audited. The project contains only Markdown documentation and provides no lockfile, hashes, signatures, or vendored source with which to verify the installed artifact. Installation and subsequent execution of a compromised package can run attacker-controlled Python code under the invoking account. This is a supply-chain exposure rather than evidence that the currently named package is malicious. Using `uv tool` or `pipx` provides useful dependency isolation, but isolation does not establish package integrity or protect credentials and user files accessible to the installed CLI at runtime. ### Attack Path 1. The package publisher account, registry entry, or release workflow is compromised. 2. An attacker publishes a malicious version newer than `0.2.1`. 3. A user follows one of the documented commands using the `>=0.2.1` constraint. 4. The resolver selects the malicious newer release. 5. Malicious code executes during installation or when the `sun` command is invoked. ### Impact Assessment A compromised dependency could execute with the privileges of the installing user. It could access the CLI's credential file, environment variables such as `SUN_TOKEN`, generated content, and other files readable by that account, and it could communicate with ...[truncated 234 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the CLI to an exact audited version rather than using a lower-bound constraint: ```bash uv tool install 'sun-cli==0.2.1' pipx install 'sun-cli==0.2.1' ``` 2. Publish cryptographic hashes for release artifacts and verify them where the package manager supports hash checking. 3. Use signed releases and document how users can verify the publisher and signature. 4. Review and approve upgrades before changing the pinned version. 5. Prefer isolated installation through `uv tool` or `pipx` over installation into the global Python environment. 6. Monitor the package registry and release workflow for unauthorized releases, and protect publisher credentials with multifactor authentication. ]]>
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 (18)

Harmful Content Injection

Critical
Category
Prompt Injection
Content
```
Sun → Spotify upload progress (5/10):
  [x] 001 — From Manya to Governess: Early Years and Formative Struggles
  [x] 002 — Paris and the Pursuit of Science
  [x] 003 — Discovering Radioactivity
  [x] 004 — Polonium and Radium: The Discovery of New Elements
  [x] 005 — Nobel Prizes and International Recognition
  [ ] 006 — generating…
  [ ] 007 — generating…
  [ ] 008 — generating…
  [ ] 009 — generating…
Confidence
70% confidence
Finding
This content may contain harmful instructions that could cause physical harm if followed. CRITICAL: Review carefully before use.

External Script Fetching

High
Category
Supply Chain
Content
The `sun` CLI is independently installable — no monorepo checkout required. Four options, in order of recommendation for external users:

```bash
# 1. curl installer (simplest — picks uv/pipx/pip automatically)
curl -fsSL https://sunapp-ai.github.io/sun-to-spotify/install.sh | bash

# 2. uv tool (manual, fastest)
Confidence
97% confidence
Finding
The documented install flow fetches and executes an external script from a remote URL. This is a classic supply-chain and arbitrary-code-execution risk, especially dangerous in a skill because users or agents may follow the command verbatim without reviewing the script contents.

Chaining Abuse

High
Category
Tool Misuse
Content
```bash
# 1. curl installer (simplest — picks uv/pipx/pip automatically)
curl -fsSL https://sunapp-ai.github.io/sun-to-spotify/install.sh | bash

# 2. uv tool (manual, fastest)
uv tool install 'sun-cli>=0.2.1'
Confidence
98% confidence
Finding
Piping remote content directly into `bash` creates an immediate command-execution chain with no inspection or integrity verification step. In agent-assisted contexts, this is particularly risky because it can transform documentation into an unsafe one-shot execution path that compromises the host environment.

Credential Access

High
Category
Privilege Escalation
Content
```

- If `sun --help` fails, the CLI isn't installed. Show the user the Install section above and ask them to confirm before running the installer. If install isn't possible, fall back to the HTTP flow in [references/http-api.md](references/http-api.md).
- If `whoami` reports unauthenticated: do **not** run `sun login` from the agent. `sun login` opens a browser for the loopback POST handoff — this won't complete in an agent context, and there is no `--email`/`--password` fallback. Ask the user to run `sun login` themselves in their terminal and re-invoke the skill. If the user is signing up for the first time, remind them to click the confirmation email link on the same machine where `sun login` is still running — the original loopback completes automatically post-confirmation, no second `sun login` needed. The same applies to the password-reset flow. For CI / fully non-interactive contexts, the user must first run `sun login` interactively on a machine with a browser, then carry the resulting `~/.config/sun/credentials.json` (or a minted `SUN_TOKEN`) over to the headless environment.
- If `whoami` reports authenticated but no active token, run `sun tokens create <name>` (`<name>` matches `^[a-z0-9-]+$`, 1-64 chars). The full secret prints to stdout once and is stored as the active token; surface it to the user but never log it elsewhere.

### 1. Create the audio job
Confidence
89% confidence
Finding
The skill instructs users to carry `~/.config/sun/credentials.json` or a minted `SUN_TOKEN` into headless/CI environments and to surface token secrets to the user. This normalizes manual credential movement and display of high-value secrets, increasing the chance of credential leakage through chat logs, shell history, CI logs, copied files, or insecure transfer channels.

External Script Fetching

High
Category
Supply Chain
Content
The `sun` CLI is self-contained — it ships and works independently of the monorepo. PyPI package name is `sun-cli`; the installed binary is `sun`. Once installed, `sun` is available on `PATH` from any directory.

### Curl installer (recommended)

```bash
curl -fsSL https://sunapp-ai.github.io/sun-to-spotify/install.sh | bash
Confidence
99% confidence
Finding
This explicitly recommends fetching and executing a remote script in one step via `curl ... | bash`, which removes any opportunity for inspection and makes compromise of the distribution channel immediately code-executing on user systems. In a skill whose purpose is to install and operate a CLI with authentication and token handling, this expands the blast radius to credential theft and full workstation compromise.

Chaining Abuse

High
Category
Tool Misuse
Content
### Curl installer (recommended)

```bash
curl -fsSL https://sunapp-ai.github.io/sun-to-spotify/install.sh | bash
```

The installer picks the first available Python package manager — `uv` (preferred), then `pipx`, then `pip --user` — and installs `sun-cli` from PyPI. If none of those is on `PATH`, the script prints install instructions and exits 1; install one and re-run.
Confidence
98% confidence
Finding
The `| bash` construct is a classic unsafe command chain because it directly feeds network-retrieved content into a shell interpreter. This turns any compromise of the remote script source, DNS, TLS termination, or publishing process into immediate arbitrary command execution with the user's privileges.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| Endpoint family | Auth | Header |
| --- | --- | --- |
| Token management (`POST/GET/DELETE /v1/public/tokens*`) | Supabase JWT | `Authorization: Bearer <jwt>` |
| Everything else (`/v1/public/courses*`, `/v1/public/whoami`) | Personal API token | `Authorization: Bearer sk_live_...` |

Token-management endpoints reject API-token auth on purpose: a leaked API token cannot mint replacements.
Confidence
80% 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).

Credential Access

High
Category
Privilege Escalation
Content
The browser flow is the only supported way to log in. There is no `--email`/`--password` or `--no-browser` fallback; headless and CI environments need to authenticate on a machine with a browser first, then carry the resulting credentials file or `SUN_TOKEN` over.

The CLI fetches the Supabase URL and anon key automatically from the public `auth-config` endpoint. The refresh token is persisted at `~/.config/sun/credentials.json` with mode `0600` on Unix.

> Verify the exact env-var names with `sun --help`. The CLI is the source of truth — older docs may use different names.
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
The browser flow is the only supported way to log in. There is no `--email`/`--password` or `--no-browser` fallback; headless and CI environments need to authenticate on a machine with a browser first, then carry the resulting credentials file or `SUN_TOKEN` over.

The CLI fetches the Supabase URL and anon key automatically from the public `auth-config` endpoint. The refresh token is persisted at `~/.config/sun/credentials.json` with mode `0600` on Unix.

> Verify the exact env-var names with `sun --help`. The CLI is the source of truth — older docs may use different names.
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill recommends executing a remote installer via `curl ... | bash`, which streams unaudited code directly into a shell. In an agent or automated workflow, this increases supply-chain risk because a compromised hosting endpoint, repository, or network path could lead to arbitrary code execution on the user's machine.

Session Persistence

Medium
Category
Rogue Agent
Content
### Save incrementally

Write the `job_id` to disk (or echo it back to the user) immediately after the `202` response. If polling crashes mid-loop, the job keeps generating server-side — re-poll with the same `job_id` rather than restarting.

### Stream — don't wait for the full course
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.

Unbounded Resource Access

Medium
Category
Excessive Agency
Content
test "$TOTAL" -eq "${#UPLOADED[@]}" || echo "WARNING: count mismatch — re-run the loop to pick up missing episodes." >&2
```

If counts disagree, re-run the streaming loop once. The CLI's `--partial` fetch re-signs URLs and fills in any episode whose `audio_url` was transiently null on the previous pass. If they still disagree, surface the gap to the user — don't loop indefinitely.

---
Confidence
75% confidence
Finding
Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The documentation recommends a curl-to-shell installer without any integrity verification, signature checking, pinning, or warning about the trust boundary. If the hosting origin, network path, or publication pipeline is compromised, users may execute arbitrary shell commands immediately on their machine.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
sun --version     # prints "sun-cli <version>"
```

macOS and Linux are first-class. Windows works for the HTTP calls but the credentials file relies on user-directory ACL, not `chmod 0600`.

### Monorepo dev install (internal contributors only)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
sun whoami                               # prints email, user_id, active token name
```

`sun login` opens the user's browser to `https://sunapp.ai/login`, where they can sign in with email + password, create a new account, or reset a forgotten password via the **"Forgot your password?"** link. The webapp posts the resulting Supabase session to a loopback listener the CLI binds; tokens never appear in any URL.

For new accounts, the user signs up with email + password, then clicks the confirmation link Supabase emails them. The link must be opened on the same machine where `sun login` is still running — the original loopback completes the handoff automatically and the CLI logs in. No second `sun login` invocation is needed. The same applies to the password-reset flow: clicking the reset link on the same machine and setting a new password completes the loopback automatically.
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.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The documentation shows a direct email/password grant flow and places credentials inline in a shell example without an explicit warning about secure handling. In an agent skill context, this can encourage implementations that collect, embed, log, or echo user passwords and exchange them with third-party services, increasing the chance of credential exposure.

External Transmission

Medium
Category
Data Exfiltration
Content
Exchange email + password for a JWT via Supabase's password grant:

```bash
JWT=$(curl -sX POST "$SUPABASE_URL/auth/v1/token?grant_type=password" \
  -H "apikey: $SUPABASE_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","password":"..."}' \
Confidence
86% confidence
Finding
This example transmits user credentials to an external authentication endpoint using a password grant. Although authentication requires network transmission by design, the risky part is that the skill documentation normalizes direct handling of raw credentials by the client/agent, which is especially dangerous for automated agents that may retain prompts, command history, or logs.

External Transmission

Medium
Category
Data Exfiltration
Content
## Mint a personal API token

```bash
curl -sX POST "$BASE/v1/public/tokens" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"name":"laptop"}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.