Back to skill

Security audit

HTML前端视频设计规范

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed presentation helper, but its optional export and sharing paths introduce review-worthy risks including public deployment, unpinned package execution, global CLI installation, and a vulnerable temporary local file server.

Install only if you are comfortable with the optional export/share features running Node-based tooling. Treat PDF export as executing unpinned Playwright and starting a temporary local server, and use Vercel deployment only for non-confidential decks because it publishes content to a public URL until removed. Prefer pinning dependencies and fixing the export server path containment before use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export-pdf.sh:165
Finding
Local HTTP Server Permits Directory Traversal and Unnecessarily Listens Beyond Loopback<![CDATA[ ## Vulnerability Details **File Location**: `scripts/export-pdf.sh`, lines 165-181 **Vulnerability Type**: Directory traversal and excessive network exposure **Risk Level**: High ### Vulnerable Code ```javascript const server = createServer((req, res) => { // Decode URL-encoded characters (e.g., %20 → space) so filenames with spaces resolve correctly const decodedUrl = decodeURIComponent(req.url); let filePath = join(SERVE_DIR, decodedUrl === '/' ? HTML_FILE : decodedUrl); try { const content = readFileSync(filePath); const ext = extname(filePath).toLowerCase(); res.writeHead(200, { 'Content-Type': MIME_TYPES[ext] || 'application/octet-stream' }); res.end(content); } catch { res.writeHead(404); res.end('Not found'); } }); // Find a free port const port = await new Promise((resolve) => { server.listen(0, () => resolve(server.address().port)); }); ``` ### Technical Analysis The temporary static-file server treats the request URL as a filesystem path after applying `decodeURIComponent()`. It then combines that value with `SERVE_DIR` using `join()` and reads the result without verifying that the normalized path remains inside the intended presentation directory. A path containing parent-directory components can therefore resolve outside `SERVE_DIR`. Encoded traversal components are particularly relevant because URL decoding occurs before filesystem resolution. The server also calls `server.listen(0)` without specifying a loopback address. Depending on the host configuration and Node.js behavior, this can bind to an unspecified address rather than strictly to `127.0.0.1`. Although the port is dynamically selected, relying on port obscurity is not an access-control mechanism. ### Attack Path 1. A user invokes `scripts/export-pdf.sh` to export a presentation. 2. The script starts the generated Node.js HTTP server. 3. The server listens on a dynamically selected port without an explicit loopback restriction. 4. A ...[truncated 1004 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind the server explicitly to the loopback interface: ```javascript server.listen(0, '127.0.0.1', () => { resolve(server.address().port); }); ``` 2. Parse only the pathname component rather than using the complete raw request URL. 3. Resolve the requested path against a canonical root and verify containment before reading it: ```javascript import { resolve, sep, extname } from 'path'; const root = resolve(SERVE_DIR); const server = createServer((req, res) => { try { const pathname = decodeURIComponent( new URL(req.url, 'http://127.0.0.1').pathname ); const relativePath = pathname === '/' ? HTML_FILE : `.${pathname}`; const filePath = resolve(root, relativePath); if (filePath !== root && !filePath.startsWith(root + sep)) { res.writeHead(403); res.end('Forbidden'); return; } const content = readFileSync(filePath); const ext = extname(filePath).toLowerCase(); res.writeHead(200, { 'Content-Type': MIME_TYPES[ext] || 'application/octet-stream', 'X-Content-Type-Options': 'nosniff' }); res.end(content); } catch { res.writeHead(404); res.end('Not found'); } }); ``` 4. Reject malformed encoding, null bytes, and paths containing unsupported path syntax. 5. Consider serving only an explicit allowlist of files discovered from the presentation rather than exposing the entire parent directory. 6. Add automated tests for plain, encoded, and double-encoded traversal attempts. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/export-pdf.sh:354
Finding
Optional Workflows Automatically Download and Execute Unpinned npm Packages<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/export-pdf.sh`, lines 354-368 - `scripts/deploy.sh`, lines 109-119 - `requirements.txt`, line 5 - `SKILL.md`, lines 238-245 and 287-290 **Vulnerability Type**: Unpinned third-party dependency retrieval and execution **Risk Level**: Medium ### Vulnerable Code From `scripts/export-pdf.sh`: ```bash # Create a minimal package.json so npm install works cat > "$TEMP_DIR/package.json" << 'PKG' { "name": "slide-export", "private": true, "type": "module" } PKG # Install Playwright into the temp directory npm install playwright &>/dev/null || { err "Failed to install Playwright." err "Try running: npm install playwright" rm -rf "$TEMP_DIR" exit 1 } # Ensure Chromium browser binary is downloaded npx playwright install chromium 2>/dev/null || { ``` From `scripts/deploy.sh`: ```bash # Check if vercel is available (either globally or via npx) if command -v vercel &>/dev/null; then VERCEL_CMD="vercel" ok "Vercel CLI found" elif npx --yes vercel --version &>/dev/null 2>&1; then VERCEL_CMD="npx --yes vercel" ok "Vercel CLI available via npx" else info "Installing Vercel CLI..." npm install -g vercel VERCEL_CMD="vercel" ok "Vercel CLI installed" fi ``` From `requirements.txt`: ```text playwright>=1.40.0 ``` ### Technical Analysis The PDF export workflow runs `npm install playwright` without an exact version or lockfile. The deployment workflow similarly invokes `npx --yes vercel`, which may retrieve and execute the currently resolved package, and falls back to a global unpinned installation with `npm install -g vercel`. The Python requirement uses an open-ended lower bound rather than a reviewed exact version. These dependency declarations do not ensure that future installations use the same code that was present when the Skill was audited. npm installation can execute package lifecycle scripts with the privileges of the invoking user. Consequently, packag ...[truncated 1893 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin exact reviewed versions rather than package names or open-ended version ranges: ```bash npm install --save-exact playwright@<reviewed-version> npx --yes vercel@<reviewed-version> --version ``` ```text playwright==<reviewed-version> ``` 2. Commit a `package-lock.json` generated from the reviewed dependency set and use: ```bash npm ci ``` This provides reproducible resolution and verifies package integrity metadata recorded in the lockfile. 3. Avoid `npm install -g vercel`. Invoke a pinned local dependency or a pinned `npx` package instead. 4. Ask for explicit user confirmation before downloading and executing packages, particularly before global installation or large browser downloads. 5. Evaluate whether lifecycle scripts can be disabled during installation: ```bash npm ci --ignore-scripts ``` If a required package genuinely needs an installation script, document and narrowly permit that step after review. 6. Pin and audit transitive dependencies through a lockfile and automated dependency scanning. 7. Verify package provenance and registry configuration. Where supported, use npm provenance data and a trusted registry allowlist. 8. Cache a reviewed Playwright browser artifact or verify downloaded browser artifacts through vendor-provided integrity mechanisms. 9. Update the “Zero Dependencies” documentation to clearly state that deployment, PPTX conversion, image processing, and PDF export introduce optional external dependencies. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented behavior goes beyond slide creation into PDF export, local HTTP serving, Playwright/Chromium installation, and automatic opening of generated files. Hidden side effects and extra execution surfaces increase risk because users may approve a 'presentation' skill without realizing it can install software and run local servers/browsers.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented behavior goes beyond slide creation into PDF export, local HTTP serving, Playwright/Chromium installation, and automatic opening of generated files. Hidden side effects and extra execution surfaces increase risk because users may approve a 'presentation' skill without realizing it can install software and run local servers/browsers.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented behavior goes beyond slide creation into PDF export, local HTTP serving, Playwright/Chromium installation, and automatic opening of generated files. Hidden side effects and extra execution surfaces increase risk because users may approve a 'presentation' skill without realizing it can install software and run local servers/browsers.

Ae1

High
Category
analysis-evasion
Content
bash scripts/export-pdf.sh <path-to-html> [output.pdf]
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
bash scripts/export-pdf.sh <path-to-html> [output.pdf]
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
bash scripts/export-pdf.sh <path-to-html> [output.pdf]
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Hidden Instructions

High
Category
Prompt Injection
Content
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Presentation Title</title>

    <!-- Fonts: use Fontshare or Google Fonts — never system fonts -->
    <link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=..." />

    <style>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Chaining Abuse

High
Category
Tool Misuse
Content
echo ""
    $VERCEL_CMD login || {
        err "Login failed. Please run 'vercel login' manually and try again."
        [[ "$CLEANUP_TEMP" == "true" ]] && rm -rf "$DEPLOY_DIR"
        exit 1
    }
    echo ""
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Chaining Abuse

High
Category
Tool Misuse
Content
echo ""
    $VERCEL_CMD login || {
        err "Login failed. Please run 'vercel login' manually and try again."
        [[ "$CLEANUP_TEMP" == "true" ]] && rm -rf "$DEPLOY_DIR"
        exit 1
    }
    echo ""
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Session Persistence

Medium
Category
Rogue Agent
Content
## What This Does

**Frontend Slides** helps non-designers create beautiful web presentations without knowing CSS or JavaScript. It uses a "show, don't tell" approach: instead of asking you to describe your aesthetic preferences in words, it generates visual previews and lets you pick what you like.

Here is a deck about the skill, made through the skill:
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.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```bash
# Create the skill directory
mkdir -p ~/.claude/skills/frontend-slides/scripts

# Copy all files (or clone this repo directly)
cp SKILL.md STYLE_PRESETS.md viewport-base.css html-template.md animation-patterns.md ~/.claude/skills/frontend-slides/
Confidence
85% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs the agent to create, modify, and delete files and directories, but the manifest does not declare any tool scope such as allowed-tools or permissions. That mismatch weakens reviewability and policy enforcement because consumers of the skill cannot easily tell that filesystem mutation is part of its behavior.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
4. **After ANY modification, verify:** `.slide` has `overflow: hidden`, new elements use `clamp()`, images have viewport-relative max-height, content fits at 1280x720
5. **Proactively reorganize:** If modifications will cause overflow, automatically split content and inform the user. Don't wait to be asked

**When adding images to existing slides:** Move image to new slide or reduce other content first. Never add images without checking if existing content already fills the viewport.

---
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest frames the skill as slide creation/conversion, but the workflow adds optional public sharing and PDF export. That scope drift matters because it introduces data egress and additional execution behavior that may not be expected from the stated purpose alone.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The Vercel deployment path enables publication of generated or converted presentations to a public URL, which is a meaningful network/data-exposure capability beyond simple local slide creation. If users place confidential deck content into the skill, this feature can accidentally expose sensitive material externally.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
Using `npx vercel --version` executes whatever package version npm resolves at runtime rather than a pinned, reviewed version. This creates a supply-chain risk where a compromised or unexpectedly changed upstream package could run code on the user's machine.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding
Using `npx vercel whoami` without version pinning has the same supply-chain execution risk as other unpinned `npx` invocations. Even a seemingly harmless identity check still requires fetching and executing package code determined at runtime.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
`npx playwright install chromium` invokes an unpinned package and then downloads and installs a browser binary, expanding the supply-chain and binary provenance risk. If the package or resolution path is compromised, arbitrary code execution or installation of untrusted components could follow.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The skill metadata is written entirely in Chinese and the trigger set is predominantly Chinese, with no indication that language selection is based on user preference or locale. This can cause mismatched activation and opaque behavior for non-Chinese users, while also biasing routing toward Chinese-language interactions without explicit consent or documented justification.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger list contains broad, everyday phrases such as '创建 PPT', '做演示', and '帮我做个演示', which can cause the skill to activate on ambiguous requests that may not specifically require this tool. Over-broad invocation increases the chance of unintended routing, exposing user content to the skill unnecessarily and causing actions or outputs the user did not explicitly request.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The HTML template hard-codes `lang="en"`, which forces an English locale choice in generated presentations. This is a natural-language locale policy constraint without any indication of user choice or justification for requiring English.

External Transmission

Medium
Category
Data Exfiltration
Content
<title>Presentation Title</title>

    <!-- Fonts: use Fontshare or Google Fonts — never system fonts -->
    <link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=..." />

    <style>
      /* ===========================================
Confidence
94% confidence
Finding
The template instructs generated presentations to load fonts from a third-party CDN, which causes viewers opening the local HTML file to make outbound network requests. This leaks metadata such as IP address, user agent, access timing, and possibly referrer/context to an external service, violating local-only expectations and creating a privacy/data exfiltration channel.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
This skill is described as creating or converting presentations, but the script also performs public hosting of user content on Vercel. That mismatch matters because users may not expect local presentation files and referenced assets to be published to an internet-accessible URL, creating a confidentiality and privacy risk.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The script installs and invokes external deployment tooling and then uploads content to a third-party service, expanding trust boundaries beyond local slide generation. In a skill whose primary purpose is presentation creation, this is risky unless clearly disclosed and justified, because it can transfer sensitive deck contents and metadata off-machine.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The script executes `npx --yes vercel` without pinning a specific package version, which causes code to be fetched and run from the npm registry at execution time. This creates a supply-chain risk: a malicious or compromised latest release could run arbitrary code on the user's machine during version checking or deployment.

Static analysis

No suspicious patterns detected.