Back to skill

Security audit

VibeTheme

Security checks for vulnerabilities and agentic risk

Overview

This theme generator is mostly coherent, but it sends user prompts to OpenRouter without telling users and returns unvalidated model-generated CSS/config output.

Review before installing. Do not enter secrets, client names, unreleased product details, or confidential branding prompts, because the vibe text is sent to OpenRouter. Treat generated CSS, Tailwind, and VS Code output as untrusted until reviewed, especially color and font values.

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

T09 · Insecure Skill Coding Practices

Warning
Location
handler.js:4
Finding

Unvalidated AI-Generated Values Allow CSS Injection

Content
View full analysis

Vulnerability Details

File Location: handler.js:4-15 and handler.js:75-79
Vulnerability Type: Unvalidated model output and unsafe CSS generation
Risk Level: Medium

The following formatter inserts AI-generated values directly into CSS declarations without validating their types or permitted syntax:

js
function toCSS(theme) {
  const vars = Object.entries({
    '--primary-color': theme.primaryColor,
    '--secondary-color': theme.secondaryColor,
    '--accent-color': theme.accentColor,
    '--background-color': theme.backgroundColor,
    '--font-stack': theme.fontStack,
  })
    .map(([k, v]) => `  ${k}: ${v};`)
    .join('\n');

  return `:root {\n${vars}\n}`;
}

The untrusted model response is parsed and passed directly to the selected formatter:

js
const data = await response.json();
const text = data.choices?.[0]?.message?.content ?? '';
const theme = JSON.parse(text);

const formatter = FORMATTERS[format] ?? FORMATTERS.css;
return formatter(theme);

Technical Analysis

The application treats an external language model's response as trusted structured data. JSON.parse confirms only that the response is syntactically valid JSON; it does not enforce a schema, primitive value types, required properties, valid color syntax, or safe font-family syntax.

In CSS mode, each returned value is interpolated verbatim into a declaration. A malicious or prompt-manipulated response could include declaration terminators, braces, comments, additional selectors, or constructs such as url(...). For example, a value containing red; } body { display: none would escape the intended custom-property declaration and add an unintended CSS rule.

Tailwind and VS Code output is protected from direct JSON syntax injection by JSON.stringify, but the values remain semantically unvalidated and may become unsafe if downstream tooling interprets them as CSS or configuration values. Malfo ...[truncated 1613 chars]

Remediation
View remediation

Remediation Suggestions

  1. Define and enforce a strict response schema requiring exactly primaryColor, secondaryColor, accentColor, backgroundColor, and fontStack as strings.
  2. Validate color fields against a narrow allowlist of supported formats, such as normalized six-digit hexadecimal colors, rather than accepting arbitrary CSS values.
  3. Replace free-form fontStack output with an allowlisted identifier mapped internally to a predefined font stack.
  4. Reject values containing declaration terminators, braces, comments, control characters, line breaks, url(), var(), or other unsupported CSS constructs.
  5. Prefer structured model output or JSON-schema response enforcement when supported by the provider, while retaining local validation because model-side enforcement is not a security boundary.
  6. Check response.ok, validate the provider response shape, and handle JSON parsing and schema failures with a controlled error.
  7. Add adversarial tests covering prompt injection, missing properties, non-string values, semicolons, braces, comments, external URLs, oversized responses, and malformed JSON.

other

Note
Location
handler.js:59
Finding

Undisclosed Transmission of User Input to an External AI Provider

Content
View full analysis

Vulnerability Details

File Location: handler.js:59-72; external processing is not disclosed in skill.md:20-43
Vulnerability Type: Undisclosed external data transmission
Risk Level: Low

The complete user-provided vibe is sent to OpenRouter:

js
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/gpt-oss-120b',
    messages: [
      { role: 'system', content: SYSTEM_INSTRUCTION },
      { role: 'user', content: vibe },
    ],
  }),
});

Technical Analysis

The implementation transmits the complete vibe value to https://openrouter.ai/api/v1/chat/completions for third-party processing. The user-facing documentation describes local inputs and generated output formats but does not state that input is sent to OpenRouter, identify the external model service, explain the network requirement, or warn users not to include confidential information.

This is not credential theft or arbitrary data harvesting: the transmitted data is limited by the observed code to the supplied vibe, system instruction, model identifier, and ordinary request metadata. However, the absence of disclosure prevents users from making an informed privacy decision before invoking the skill.

Attack Path

  1. A user assumes the theme-generation operation is local because external processing is not documented.
  2. The user includes confidential project details, an unreleased product description, client information, or other sensitive text in the vibe parameter.
  3. generateTheme embeds the complete value in the request body.
  4. The application sends the request to OpenRouter over HTTPS.
  5. OpenRouter and any model-processing infrastructure involved in fulfilling the request receive and process the submitted content according to their applicable policies.

...[truncated 610 chars]

Remediation
View remediation

Remediation Suggestions

  1. Update skill.md to clearly state that the complete vibe value is sent to OpenRouter and identify the API endpoint or provider.
  2. Explain what data is transmitted, why it is necessary, and that users should not submit secrets, credentials, personal data, or confidential project information.
  3. Obtain explicit user consent before the first external transmission where the host platform supports consent prompts.
  4. Provide a configurable provider endpoint or a local/offline generation option where feasible.
  5. Minimize submitted content and enforce a reasonable maximum input length.
  6. Document relevant retention and privacy considerations, and provide links to the external provider's applicable terms and privacy policy.
  7. Continue using HTTPS and add controlled handling for network failures, non-success HTTP responses, unexpected content types, and oversized responses.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The description partially matches the code's theme-generation intent, but it understates key behavior. The code does not just generate a color palette and CSS variables; it sends user input to an external API and can output Tailwind and VS Code configuration formats in addition to CSS. Those are materially broader capabilities and involve external resource access that is not declared in the permissions or description.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The stated skill purpose is limited to generating a color palette and CSS variables based on an atmosphere. In addition to CSS variables, the implementation formats the generated theme into Tailwind config and VS Code workbench/editor customization JSON, which extends beyond the manifest's described output scope.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The skill makes an outbound network request to an external LLM endpoint, which creates a real data exfiltration path for any prompt content supplied by the user. In this context, the skill's purpose does not inherently require secrecy, but absent disclosure and safeguards, external transmission still poses privacy and compliance risks.

Content

Scanner excerpt · handler.js (reported line 64)May include surrounding context.

js
// --- Main ---

async function generateTheme(vibe, format = 'css') {
  const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

User-supplied input is transmitted to a third-party API service without any visible notice, consent, or data-handling controls. This is dangerous because users may provide sensitive project names, internal branding details, or proprietary design prompts that are then exposed to an external processor unexpectedly.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

Generating IDE-specific settings such as workbench and editor customization JSON is a distinct capability from producing a palette and CSS variables. That output target is not implied by the manifest description and broadens the skill into editor theming without declaring that intent.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.