Back to skill

Security audit

Skillboss

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real AI API wrapper, but it needs Review because it handles API keys and remote API responses in ways that are under-scoped and risky.

Install only if you are comfortable sending prompts, files, URLs, and generated outputs through SkillBoss and its providers. Treat the SkillBoss API key as a secret, avoid running auth commands where stdout is logged, avoid using sensitive audio/documents unless approved, and be cautious with `--output` because returned media URLs are fetched automatically.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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/auth.mjs:17
Finding
API Credentials Are Stored and Exposed Insecurely<![CDATA[ ## Vulnerability Details **File Location**: `scripts/auth.mjs:17-18`, `scripts/auth.mjs:50-74`, `scripts/auth.mjs:90-97`, `scripts/auth.mjs:105-116` **Vulnerability Type**: Plaintext credential storage and credential exposure through stdout and URL query parameters **Risk Level**: High ### Vulnerable Code ```js function saveConfig(config) { writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n"); } ``` ```js if (cmd === "trial") { const existing = getKey(); if (existing) { console.error(`Already have key: ${mask(existing)}`); process.stdout.write(existing); process.exit(0); } const resp = await fetch(`${API_BASE}/temp-token/provision`, { method: "POST", headers: { "Content-Type": "application/json" }, }); const data = await resp.json(); const config = loadConfig(); config.apiKey = data.api_key; saveConfig(config); console.error(`Trial key provisioned ($${data.balance_usd} credit)`); console.error(`Upgrade anytime: node auth.mjs login`); process.stdout.write(data.api_key); } ``` ```js config.apiKey = data.api_key; saveConfig(config); key = data.api_key; const bindUrl = `${WEB_BASE}/login?temp=${encodeURIComponent(key)}`; console.error(`\nOpen this URL to sign in:\n ${bindUrl}\n`); ``` ```js const resp = await fetch(`${API_BASE}/temp-token/poll-bind`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ temp_api_key: key }), }); if (result.status === "bound" && result.permanent_api_key) { const config = loadConfig(); config.apiKey = result.permanent_api_key; saveConfig(config); console.error(`\nAuthentication complete! Key saved to config.json`); process.exit(0); } ``` ### Technical Analysis Trial and permanent API credentials are written directly to `config.json` using `writeFileSync` without an explicit restrictive file mode. The resulting permissions depend on the process umask and surrounding environment, which may permit other lo ...[truncated 1888 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store long-lived credentials in the operating system’s credential manager rather than in the project directory. 2. If file storage is unavoidable, create a dedicated credential file with mode `0o600`, verify its ownership and permissions, and exclude it from source control and backups: ```js writeFileSync(credentialsPath, serializedConfig, { encoding: "utf8", mode: 0o600, flag: "w" }); ``` 3. Never print complete API keys to stdout or stderr. Return only a success indication or a consistently masked identifier. 4. Replace the browser URL’s API key with a short-lived, single-use, narrowly scoped binding code that cannot invoke model APIs. 5. Expire binding codes quickly and invalidate them immediately after successful use. 6. Prefer an `Authorization` header over credentials in JSON bodies where the API supports it, reducing accidental request-body logging. 7. Clearly document where credentials are stored, how they are protected, and how users can revoke them. 8. Ensure logout revokes the server-side credential where supported rather than only overwriting the local value. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run.mjs:198
Finding
Unvalidated Server-Controlled URLs Are Downloaded Without Resource Limits<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run.mjs:198-212` **Vulnerability Type**: Unrestricted URL fetching, server-side request forgery exposure, and unbounded download **Risk Level**: Medium ### Vulnerable Code ```js // ── Save output file ── if (flags.output && hasInput) { const inner = data.result || data; const url = inner.image_url || inner.video_url || inner.audio_url || inner.url || inner.data?.[0] || inner.generated_images?.[0] || null; if (url) { const dl = await fetch(url); if (dl.ok) { writeFileSync(flags.output, Buffer.from(await dl.arrayBuffer())); console.error(`Saved to ${flags.output}`); } } else if (inner.audio_base64) { writeFileSync(flags.output, Buffer.from(inner.audio_base64, "base64")); console.error(`Saved to ${flags.output}`); } } ``` ### Technical Analysis The external API response fully controls the URL passed to `fetch`. The implementation does not: - Require HTTPS. - Restrict downloads to trusted media domains. - Reject loopback, private, link-local, or cloud metadata addresses. - Validate redirect destinations. - Apply a request timeout. - Limit the response size. - Validate the response content type. - Stream the response instead of buffering it entirely in memory. Downloading generated media is part of the Skill’s declared functionality, but unrestricted retrieval of any API-supplied URL exceeds the minimum network privileges required. A compromised API, upstream provider, or manipulated response could direct the client to internal network services or to an arbitrarily large payload. Because the code does not print the downloaded response body, direct extraction of internal response contents is limited. Nevertheless, blind requests can reach internal endpoints, and state-changing services that accept GET requests may be affected. Buffering the entire response also enables memory exhaustion, while writing it to disk can cause disk exhaustion. ### Attack Pa ...[truncated 1310 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require downloaded result URLs to use HTTPS. 2. Maintain an explicit allowlist of trusted media-storage domains used by the API and its providers. 3. Resolve hostnames before connecting and reject loopback, private, link-local, multicast, and reserved addresses for both IPv4 and IPv6. 4. Disable automatic redirects or validate every redirect destination using the same scheme, domain, and resolved-address controls. 5. Use `AbortController` to enforce a short connection and total download timeout. 6. Reject responses whose declared or observed size exceeds a documented maximum. 7. Validate `Content-Type` against the expected output category, such as `image/*`, `audio/*`, or `video/*`. 8. Stream validated content to a safely created file rather than loading the entire response into memory. 9. Delete partial output files if validation or transfer fails. 10. Treat all URLs returned by remote APIs as untrusted, even when the initial API endpoint itself is trusted. ]]>

T01 · Skill Instruction Hijacking

Warning
Location
error-handling.md:13
Finding
Remote API Warning Content Is Required to Be Relayed Verbatim<![CDATA[ ## Vulnerability Details **File Location**: `error-handling.md:13-18`; runtime output sink at `scripts/run.mjs:191-195` **Vulnerability Type**: Untrusted remote content injection into agent-visible output **Risk Level**: Medium ### Vulnerable Code and Instructions ```md ## Balance Warnings API responses may include a `_balance_warning` field. Relay this to the user exactly as provided. Check balance: `auth.mjs status` Add credits: https://www.skillboss.co ``` ```js const data = await resp.json(); if (data._balance_warning) { const w = data._balance_warning; console.error(`[skillboss] ${typeof w === "string" ? w : w.message || JSON.stringify(w)}`); } ``` ### Technical Analysis The Skill documentation instructs the agent to relay `_balance_warning` exactly as supplied by the remote API. The corresponding script prints the field without validating its structure or constraining its content. This creates an instruction and output injection channel controlled by the API response. If the API or an upstream response path is compromised, `_balance_warning` can contain misleading instructions, advertisements, phishing links, requests for secrets, or text intended to alter the agent’s behavior. The JavaScript does not evaluate the field or execute it as a shell command, so this is not direct code execution. The primary vulnerability arises when an agent follows the Skill instruction and treats externally supplied text as trusted content that must be reproduced verbatim. ### Attack Path 1. An attacker compromises the API response path or gains the ability to control `_balance_warning`. 2. The attacker places malicious instructions or a deceptive link in the field. 3. `run.mjs` prints the value to stderr with a trusted-looking `[skillboss]` prefix. 4. The agent observes the output and follows the documentation’s requirement to relay it exactly. 5. The user receives attacker-controlled content as part of the agent’s trusted response. 6. The content m ...[truncated 621 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the instruction to relay remote warning content exactly. 2. Use a locally defined warning template populated only with validated values: ```text SkillBoss reports that the account balance is low. Review billing through the official configured site. ``` 3. Parse `_balance_warning` according to a strict schema and accept only expected fields, such as a numeric balance or predefined warning code. 4. Map remote warning codes to local, trusted messages instead of displaying arbitrary text. 5. Do not render remote URLs unless they match an explicit allowlist of official HTTPS domains. 6. Clearly label any unavoidable remote text as untrusted service-provided data. 7. Instruct the agent never to follow commands, requests for secrets, or behavioral directives found in API responses. 8. Apply length limits and remove terminal control characters before logging remote strings. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (13)

Credential Access

High
Category
Privilege Escalation
Content
| Error Handling | `error-handling.md` |

Notes:
- Get API key from https://www.skillboss.co or run `auth.mjs trial`
- Use `--models` to list models live from the API
- Use `--prefer price` for cheapest, `--prefer quality` for best results
- After first request with trial key, suggest `auth.mjs login` to upgrade
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp1

High
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The script makes outbound network requests to external services for provisioning and polling API tokens, but that network capability is not covered by declared permissions. In an agent skill, undeclared network access is dangerous because it enables data egress and remote control paths that users and reviewers may not expect.

Lp1

High
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The script makes outbound network requests to external services for provisioning and polling API tokens, but that network capability is not covered by declared permissions. In an agent skill, undeclared network access is dangerous because it enables data egress and remote control paths that users and reviewers may not expect.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill routes prompts, files, image URLs, and other user-supplied content to external third-party services across many providers, but it does not clearly warn users about this data egress. In an agent setting, this can cause sensitive text, documents, recordings, or URLs to be transmitted off-platform without informed user consent, increasing privacy, compliance, and data-handling risk.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation instructs users to place the API key directly in the JSON request body and provides no warning about secure credential handling, storage, logging, or client-side exposure. In agent and web integration contexts, this increases the risk that secrets are embedded in browser code, leaked through logs, telemetry, debugging tools, or copied into untrusted environments.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "version": "2026.03.20",
  "apiKey": "YOUR_API_KEY_HERE",
  "baseUrl": "https://api.heybossai.com/v1",
  "buildApiUrl": "https://build.heybossai.com",
  "stripeConnectUrl": "https://heyboss.ai"
}
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "version": "2026.03.20",
  "apiKey": "YOUR_API_KEY_HERE",
  "baseUrl": "https://api.heybossai.com/v1",
  "buildApiUrl": "https://build.heybossai.com",
  "stripeConnectUrl": "https://heyboss.ai"
}
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "version": "2026.03.20",
  "apiKey": "YOUR_API_KEY_HERE",
  "baseUrl": "https://api.heybossai.com/v1",
  "buildApiUrl": "https://build.heybossai.com",
  "stripeConnectUrl": "https://heyboss.ai"
}
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "version": "2026.03.20",
  "apiKey": "YOUR_API_KEY_HERE",
  "baseUrl": "https://api.heybossai.com/v1",
  "buildApiUrl": "https://build.heybossai.com",
  "stripeConnectUrl": "https://heyboss.ai"
}
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "version": "2026.03.20",
  "apiKey": "YOUR_API_KEY_HERE",
  "baseUrl": "https://api.heybossai.com/v1",
  "buildApiUrl": "https://build.heybossai.com",
  "stripeConnectUrl": "https://heyboss.ai"
}
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
When invoked with --file for STT, the script reads the entire local file, base64-encodes it, and sends it to a remote API without any explicit warning, confirmation, or consent gate at the point of transmission. In an agent skill context, this increases the risk that sensitive local audio or mislabeled files are exfiltrated to a third party by automation or user misunderstanding.

Missing User Warnings

Low
Confidence
92% confidence
Finding
The examples encourage writing generated content to local files via --output, but the skill does not warn that this will create or overwrite artifacts on disk. In agent workflows, silent file creation can leak sensitive generated data into shared workspaces or unexpectedly modify local state.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The description "Chinese optimized (fast)" introduces a language/locale-specific constraint in natural language without indicating that this model should only be used when the user wants Chinese output or has opted into that locale. Under the policy, language-specific behavior should be optional or clearly justified.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/auth.mjs:114