Back to skill

Security audit

Poster Designer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a poster-generation helper, but one included composition script can turn normal poster text into local command execution when ImageMagick is available.

Review before installing. Use the Gemini generation part only with a protected API key, and avoid running the composition helper on untrusted poster text or paths until it replaces shell command construction with argument-based process execution and sanitizes fallback HTML.

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

Error
Location
scripts/compose-poster.js:273
Finding

Shell Command Injection in ImageMagick Composition

Content
View full analysis
{ const fontSize = el.size === 'large' ? 48 : el.size === 'medium' ? 32 : 24; const fontWeight = el.weight === 'bold' ? 'bold' : 'normal'; // Calculate position (simplified) let x = 50; // percentage let y = 10 + idx * 15; // percentage if (el.position.includes('center')) x = 50; if (el.position.includes('bottom')) y = 80 + idx * 10; if (el.position.includes('left')) x = 25; if (el.position.includes('right')) x = 75; cmd += ` \\\n -gravity center \\\n -fill white \\\n -stroke black \\\n -strokewidth 2 \\\n -pointsize ${fontSize} \\\n -annotate +0+${(idx - 2) * 60} "${el.text.replace(/"/g, '\\"')}"`; }); cmd += ` "${outputPath}"`; return cmd; } ``` The generated string is subsequently passed to a shell: ```javascript if (hasImageMagick) { // Use ImageMagick const cmd = generateImageMagickCommand(options.image, elements, outputPath); console.error('Running ImageMagick composition...'); execSync(cmd, { stdio: 'inherit' }); result.composed = true; result.method = 'imagemagick'; } ``` ### Technical Analysis The script accepts the input image path, output path, title, subtitle, date, venue, and call-to-action text from command-line arguments. These values are interpolated into one command string that is passed to `child_process.execSync()`. Because `execSync()` executes the string through a system shell, shell metacharacters and substitutions in these arguments are interprete ...[truncated 2477 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/compose-poster.js:241
Finding

HTML and Script Injection in Fallback Poster Composition

Content
View full analysis
${elements.filter(e => e.position.includes('top')).map(e => `
${e.text}
` ).join('')}
${elements.filter(e => e.position.includes('center')).map(e => `
${e.text}
` ).join('')}
${elements.filter(e => e.position.includes('bottom') || e.position.includes('above-bottom')).map(e => e.type === 'cta' ? `
${e.text}
` : `${e.text}` ).join('')}
``` The resulting document is written without sanitization: ```javascript const htmlPath = outputPath.replace(/\.[^/.]+$/, '') + '.html'; fs.writeFileSync(htmlPath, html); return htmlPath; ``` ### Technical Analysis When ImageMagick is unavailable, the script creates an HTML fallback and tells the user to open it in a browser. Poster text originating from `--title`, `--subtitle`, `--date`, `--venue`, and `--cta` is inserted directly into HTML text contexts. No HTML encoding or sanitization is applied. Consequently, characters such as `<`, `>`, `&`, and quotes retain their markup meaning. An attacker can terminate the intended element and introduce arbitrary HTML, including active browser content. The basename of the user-selected image path is also inserted directly into a double-quoted `src` attribute. A filename conta ...[truncated 1983 chars]
Remediation
View remediation
/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } ``` 2. Apply escaping to every `e.text` value and to `imageName` before constructing the template. 3. Prefer a maintained templating library that enables automatic contextual escaping by default. 4. Avoid accepting arbitrary HTML as poster text. If rich formatting is later required, sanitize it with a well-maintained allowlist-based HTML sanitizer. 5. Add a restrictive Content Security Policy to the generated document, for example one that disables scripts, plugins, frames, and remote connections unless explicitly required. 6. Consider embedding the image as a validated data URL or copying it to a controlled filename next to the generated document instead of inserting an attacker-influenced filename. 7. Validate image filename extensions and MIME signatures before including files in the fallback. 8. Add regression tests for element-breaking markup, quoted attribute injection, event-handler attributes, script elements, malformed tags, and entity-encoded payloads. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill advertises Gemini-based AI image generation and template-driven poster creation, but the static finding indicates the actual behavior does not perform that integration and instead operates on local image compositing. This kind of description-behavior mismatch can mislead users and reviewers about what code will do, weakening trust and potentially hiding unexpected local file handling or other undisclosed behavior.

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

md
const fs = require('fs');
const path = require('path');

// Load .env file if present
const envPath = path.join(__dirname, '..', '.env');
if (fs.existsSync(envPath)) {
  const envContent = fs.readFileSync(envPath, 'utf-8');

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

md
const fs = require('fs');
const path = require('path');

// Load .env file if present
const envPath = path.join(__dirname, '..', '.env');
if (fs.existsSync(envPath)) {
  const envContent = fs.readFileSync(envPath, 'utf-8');

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/generate-poster.js (reported line 17)May include surrounding context.

js
const fs = require('fs');
const path = require('path');

// Load .env file if present
const envPath = path.join(__dirname, '..', '.env');
if (fs.existsSync(envPath)) {
  const envContent = fs.readFileSync(envPath, 'utf-8');

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/generate-poster.js (reported line 18)May include surrounding context.

js
const path = require('path');

// Load .env file if present
const envPath = path.join(__dirname, '..', '.env');
if (fs.existsSync(envPath)) {
  const envContent = fs.readFileSync(envPath, 'utf-8');
  envContent.split('\n').forEach(line => {

External Model or Provider Selection

High
Category
Excessive Agency
Confidence
90% confidence
Finding

Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Content

Scanner excerpt · scripts/generate-poster.js (reported line 238)May include surrounding context.

js
--color                 Color scheme description
  --aspect-ratio, -a      Aspect ratio: 1:1, 4:3, 16:9, 9:16, 3:4 (default: 1:1)
  --size, -s              Image size: 1K, 2K, 4K (default: 2K)
  --model, -m             Gemini model to use
  --output, -o            Output file path (default: ./poster.png)
  --json                  Output JSON with metadata
  --help, -h              Show this help

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/generate-poster.js (reported line 290)May include surrounding context.

js
prompt += `\nInclude visual elements that complement "${options.title}".`;
  }

  return prompt;
}

// Map aspect ratio to Gemini-supported ratio

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.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation explicitly allows passing the Gemini API key as a query parameter without warning about leakage risks. Query-string credentials are commonly exposed through logs, browser history, proxies, referrers, and monitoring systems, which can lead to unauthorized API use and cost abuse if the key is captured.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The example user-facing message is presented in Chinese as the primary output, with English only as a parenthetical translation. This indicates a default language choice for end users without any opt-in, selection mechanism, or stated regional limitation, which violates the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The HTML fallback writes unescaped user-controlled text directly into an HTML document and interpolates the image filename into an attribute, creating a stored HTML/script injection issue if the generated file is opened in a browser. Although this fallback is framed as a composition aid, the skill accepts attacker-controlled title, subtitle, venue, and CTA fields, so opening the output can execute arbitrary JavaScript in the local browser context. The mismatch with the skill's stated image output also increases the chance users may trust and open the file without recognizing it as active content.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script builds a shell command string and executes it with child_process.execSync using user-controlled fields such as imagePath, outputPath, and especially text overlay content. Only double quotes in text are escaped, leaving shell metacharacters like $(...), backticks, and potentially crafted paths able to trigger command injection when passed through the shell. In a poster-design skill, this is more dangerous because user-supplied poster text is expected and attacker-controlled, making exploitation realistic.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/compose-poster.js:325