Back to skill

Security audit

html-ppt-zc

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a presentation generator, but its HTML output path and template have under-disclosed browser risks that users should review before installing.

Install only if you are comfortable reviewing or modifying the HTML behavior. Prefer PPTX output for ordinary use; treat HTML output as unsafe for untrusted text, and avoid opening or sharing generated HTML until user input is escaped and remote CDN/font dependencies are removed or clearly accepted.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
generate_ppt.py:39
Finding

Stored HTML Injection in Generated Presentations

Content
View full analysis
{}".format(title)] for idx, para in enumerate(paragraphs): html_parts.append(f"

Slide {idx+1}

text
{para}
") html_parts.append("") with open(output_path, 'w', encoding='utf-8') as f: f.write('\n'.join(html_parts)) print(f'HTML slide deck saved to {output_path}') ``` ### Technical Analysis The `--title` and `--text` command-line values are directly interpolated into an HTML document without context-appropriate encoding. The `
text
` element does not make its contents safe: an attacker can close it and introduce arbitrary HTML or JavaScript.

For example, attacker-controlled text containing the following payload would create an executable script in the generated presentation:

```html
text
```

The title is also vulnerable because it is inserted directly into the `` element and can be escaped with a payload containing ``.

### Attack Path

1. An attacker supplies or influences the title or body text used to generate a presentation.
2. The Skill is invoked with `--html`.
3. `export_html()` writes the attacker-controlled value directly into the output document.
4. A user opens the generated HTML presentation in a browser.
5. The injected markup or JavaScript executes in the generated page's browser context.

### Impact Assessment

Successful exploitation allows arbitrary JavaScript to execute in the presentation page. The attacker could:

- Replace or manipulate the displayed presentation.
- Create deceptive login f
...[truncated 465 chars]
Remediation
View remediation
", "", "", f"{safe_title}", ] for idx, para in enumerate(paragraphs): safe_para = escape(para, quote=True) html_parts.append( f"
" f"

Slide {idx + 1}

text
{safe_para}
" ) html_parts.append("") with open(output_path, "w", encoding="utf-8") as f: f.write("\n".join(html_parts)) ``` Alternatively, use Jinja2 with HTML autoescaping explicitly enabled. Add regression tests covering closing tags, event-handler attributes, encoded payloads, and `

T03 · Remote Payload Retrieval and Execution

Warning
Location
assets/template.html:670
Finding

Mutable Remote JavaScript Is Downloaded and Executed

Content
View full analysis
``` ### Technical Analysis The template loads JavaScript from an external CDN using the mutable `@latest` package alias. The effective executable payload can therefore change after the Skill has been reviewed. No Subresource Integrity hash is provided to verify the downloaded response. The browser executes the CDN response with the privileges of the generated presentation page. Compromise of the CDN, package publication process, package maintainer account, or a future package release could introduce arbitrary JavaScript. Opening the presentation also makes an external request and exposes ordinary network metadata, including the viewer's IP address, user agent, referrer behavior, and request timing, to the remote provider. The current `generate_ppt.py` implementation does not use this template. Consequently, this attack path becomes reachable when the bundled template is opened directly or incorporated into an HTML presentation by another workflow. ### Attack Path 1. A presentation is created from or directly uses `assets/template.html`. 2. A user opens the presentation while network access is available. 3. The browser requests `lucide@latest` from UNPKG. 4. UNPKG returns the current package payload, which is not bound to the reviewed version or an integrity hash. 5. The browser executes the returned JavaScript in the presentation page. 6. If the remote package or distribution channel is compromised, attacker-controlled code gains control of the page. ### Impact Assessment A malicious remote response could: - Read and modify all presentation DOM content. - Replace slides with deceptive or malicious content. - Capture keybo ...[truncated 504 chars]
Remediation
View remediation
``` If remote loading is unavoidable: 1. Replace `@latest` with an exact immutable version. 2. Add a verified Subresource Integrity hash. 3. Set `crossorigin="anonymous"`. 4. Apply a restrictive Content Security Policy that allows scripts only from explicitly approved sources. 5. Document that opening the presentation performs external network requests. Example: ```html ``` Local vendoring is preferable because it makes the presentation reproducible, reviewable, and usable offline. ]]>

T03 · Remote Payload Retrieval and Execution

Note
Location
assets/template.html:679
Finding

Remote Motion Module Executes When the Local Dependency Fails

Content
View full analysis
let motion; try { motion = await import('./assets/motion.min.js'); } catch(e1) { try { motion = await import('https://cdn.jsdelivr.net/npm/motion@11.11.17/+esm'); ``` ### Technical Analysis The template first imports the bundled Motion library, but automatically downloads and executes a remote JavaScript module if the local import fails. The remote URL pins version `11.11.17`, which is safer than a mutable `latest` alias, but the dynamically imported module is not protected by Subresource Integrity. A local import can fail if the asset is omitted during packaging, moved, blocked, or served under an incompatible configuration. Under those conditions, the CDN response becomes an executable payload controlled outside the audited project. The bundled local file identifies itself as Motion version `11.11.17`; no separate credential access, persistence, network communication, or dynamic-evaluation behavior was identified in that local library. The risk arises from the automatic remote fallback. As with the preceding finding, `generate_ppt.py` does not currently consume this template. The path is reachable when the template is opened directly or used by an external generation workflow. ### Attack Path 1. A presentation uses `assets/template.html`. 2. The browser attempts to import `./assets/motion.min.js`. 3. The local import fails because the asset is missing, inaccessible, or blocked. 4. The exception handler imports Motion from jsDelivr. 5. The browser downloads and executes the CDN response. 6. A compromised package-distribution path or CDN response can execute attacker-controlled code in the presentation page. ### Impact Assessment A malicious fallback module would execute with presentation-page privileges and ...[truncated 433 chars]
Remediation
View remediation
{ el.style.opacity = '1'; el.style.transform = 'none'; }); document .querySelectorAll('[data-animate="pipeline"] [data-anim]') .forEach((el) => { el.style.opacity = '1'; }); } ``` Additional hardening should include: 1. Ensure `assets/motion.min.js` is always included during packaging. 2. Record and verify a cryptographic checksum for the bundled file. 3. Pin the bundled dependency version in build documentation. 4. Use a restrictive Content Security Policy that does not permit arbitrary remote module imports. 5. Add a packaging test that verifies all locally referenced assets exist before release. ]]>
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says this skill generates PowerPoint or HTML presentations using python-pptx. However, the provided code chunk is unrelated JavaScript for frontend motion/animation behavior. It manipulates DOM/SVG elements, schedules animation frames, handles easing/springs/keyframes, and integrates with browser APIs like requestAnimationFrame, ResizeObserver, IntersectionObserver, and Web Animations. There is no evidence of Python code, pptx generation, file output, or presentation-building logic. This is a clear description-behavior mismatch with a materially different primary purpose.

Content

No source excerpt is available for this finding.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · assets/template.html (reported line 434)May include surrounding context.

html
<div id="deck">

<!-- ============================================================
     SLIDES 插入区 · 在此处填充所有 <section class="slide ..."> 页面
     每页模板参考 references/page-patterns.md
     页面组件参考 references/components.md

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.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language instructions and usage guidance are presented in Chinese throughout the file, but the skill does not state that it is Chinese-only or offer an alternative language based on user preference. Per the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The HTML root sets lang="zh-CN", which fixes the document language/locale to Simplified Chinese. Under the policy, forcing a specific language without user opt-in or clear justification is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template loads Google Fonts from external domains, which causes generated presentations to make unsolicited outbound network requests when opened. That creates privacy and supply-chain risk, breaks offline use, and allows third parties to observe usage metadata or alter delivered assets if the remote resource is compromised.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The generated HTML imports runtime JavaScript from unpkg and jsDelivr, adding undocumented remote code execution in the browser context whenever the presentation is opened. Even if intended for icons and animation, these dependencies enlarge the attack surface, undermine reproducibility, and expose users to CDN compromise or tracking.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

A presentation generator does not inherently require live third-party script dependencies at view time, so the external CDNs are not justified by the stated skill purpose. This makes generated outputs less trustworthy and can execute third-party code in environments that expect a self-contained local artifact.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file documents commands that generate .pptx or .html output files, but it does not explicitly warn users that the operation writes to disk and may overwrite an existing file at the --output path. For markdown files, user-facing descriptions should disclose behaviors that can affect user data or system state.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The template loads fonts from Google-hosted domains, which causes network requests to third parties when the file is opened. There is no nearby comment, prompt, or other disclosure warning users that opening the template will contact external services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The page loads Lucide from unpkg.com, which triggers a third-party network request at runtime. The file does not provide a user-facing warning or disclosure that using the template depends on remote CDN resources.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest says the skill can generate either PPT or HTML presentations, but only the PPT path ensures the output directory exists before writing. In the HTML path, the code writes directly to the provided path, so generation may fail for valid nested output locations, making the advertised HTML capability inconsistently implemented.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.