Back to skill

Security audit

z-article-card

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a disclosed article-to-card renderer, but it can render fetched or pasted Markdown as active HTML in an unsandboxed browser, which needs review before installation.

Review before installing. Use this only in an isolated environment with no secrets, avoid rendering attacker-controlled Markdown or arbitrary URLs, disable or sanitize raw HTML before rendering, remove --no-sandbox if possible, pin the markdown dependency, and replace the default footer/avatar branding before publishing generated images.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T01 · Skill Instruction Hijacking

Warning
Location
assets/templates/poster-3-4.html:93
Finding
Generated images contain hardcoded third-party attribution<![CDATA[ ## Vulnerability Details **File Location**: `assets/templates/poster-3-4.html:93-97` **Additional Locations**: `scripts/render_article.py:197`, `scripts/render_card.py:51`, `SKILL.md:32-52`, `references/article-3-4.md:70-71` **Vulnerability Type**: Persistent output modification through hardcoded promotional branding **Risk Level**: Medium ### Vulnerable Code ```html <div class="watermark"> <img src="{{AVATAR_PATH}}" alt="Jinx"> <span>✦ made by Jinx · {{FOOTER_TEXT}}</span> </div> ``` The rendering scripts also assign a third-party promotional footer as the default value of the configurable footer argument. ### Technical Analysis The poster template unconditionally adds the fixed attribution `made by Jinx` and a Jinx-branded avatar to every generated poster. Changing the configurable `FOOTER_TEXT` value does not remove this fixed attribution. The article and poster renderers also default to footer text associated with third-party social-media branding. Consequently, invoking the Skill through its documented default workflow modifies the user's requested image with promotional content that is not necessary for image generation. This behavior is best classified as instruction/output hijacking because the Skill's default instructions and templates cause the agent to produce persistent third-party promotional output rather than only the user-requested content. ### Attack Path 1. A user asks the agent to convert text into a card or poster. 2. The agent invokes the documented rendering workflow without explicitly overriding every branding-related field. 3. The renderer loads the bundled template. 4. The template adds the fixed avatar and `made by Jinx` text. 5. Headless Chrome captures the branded page as a PNG. 6. The resulting image may be published or redistributed by the user without realizing that it contains third-party promotion. ### Impact Assessment The impact is limited to generated content; this issue does not grant filesystem, ...[truncated 302 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the fixed `made by Jinx` text and branded avatar from the template. 2. Default the footer and avatar to empty values. 3. Add branding only when the user explicitly requests it. 4. Provide a documented `--branding` or `--attribution` option that is disabled by default. 5. Ensure that changing the footer removes all bundled attribution, not only the configurable footer segment. 6. Add rendering tests that verify default output contains no third-party names, logos, avatars, or promotional text. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/render_article.py:121
Finding
Untrusted Markdown is rendered as active HTML in an unsandboxed browser<![CDATA[ ## Vulnerability Details **File Location**: `scripts/render_article.py:121-127` **Related Locations**: `scripts/render_article.py:143-174`, `assets/templates/article-3-4.html:125-127` **Vulnerability Type**: Unsafe HTML rendering and browser execution **Risk Level**: High ### Vulnerable Code ```python def text_to_html(text: str) -> str: """Render the entire text through Markdown with full Markdown syntax.""" try: import markdown as md_lib except ImportError: sys.exit('The markdown package must be installed.') return md_lib.markdown(text, extensions=['fenced_code', 'tables', 'nl2br']) ``` The resulting HTML is inserted directly into the template: ```python replacements = { '{{MD_CSS_PATH}}': str(md_css_path) if md_css_path else '', '{{TITLE}}': escape(title), '{{CONTENT_HTML}}': content_html, '{{PAGE_LABEL}}': escape(page_label), '{{BOTTOM_TIP}}': escape(bottom_tip), '{{HIGHLIGHT_COLOR}}': highlight, '{{BG_COLOR}}': bg, '{{FOOTER_TEXT}}': escape(footer), '{{ICON_PATH}}': icon_path, '{{AVATAR_PATH}}': avatar_path, '{{FONT_PATH}}': font_path, } ``` The generated document is then opened with sandboxing disabled: ```python cmd = [ chrome, '--headless', '--disable-gpu', '--no-sandbox', f'--screenshot={out_path}', f'--window-size={W},{H}', f'file://{tmp_html}', ] result = subprocess.run(cmd, capture_output=True) ``` The template insertion point is: ```html <div class="content"> {{CONTENT_HTML}} </div> ``` ### Technical Analysis Python-Markdown allows raw HTML from the input to pass through unless a separate sanitization step is applied. The renderer inserts the resulting fragment into the HTML template without escaping or sanitizing it. An attacker-controlled article can therefore contain active HTML, including script elements, inline event handlers, iframes, or remote resource references. When headless Chrome opens the temporary document, that content ...[truncated 1849 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject or escape raw HTML before Markdown conversion when raw HTML is not required. 2. Sanitize generated HTML with a strict allowlist-based sanitizer. 3. Permit only necessary formatting elements such as paragraphs, headings, lists, emphasis, tables, and code blocks. 4. Remove script elements, iframes, objects, embedded content, form elements, inline event handlers, `javascript:` URLs, and unsafe SVG content. 5. Restrict links and image sources to approved schemes and hosts, or disable remote resources entirely. 6. Remove `--no-sandbox` and run Chrome with its normal sandbox enabled. 7. Execute the renderer in a low-privilege container or dedicated account with no secrets and minimal filesystem access. 8. Disable outbound network access for the rendering process unless explicitly required. 9. Apply CPU, memory, execution-time, and output-size limits. 10. Add security tests using raw HTML, event handlers, remote resources, iframes, and malformed Markdown. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:10
Finding
Runtime dependency is installed without version or integrity pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:10-14` **Related Locations**: `scripts/render_article.py:121-127`, `scripts/render_article.py:130-136` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Code ```markdown ## Environment Requirements - Python 3 - Google Chrome - `pip install markdown` ``` The dependency is imported at runtime: ```python try: import markdown as md_lib except ImportError: sys.exit('The markdown package must be installed.') return md_lib.markdown(text, extensions=['fenced_code', 'tables', 'nl2br']) ``` ### Technical Analysis The documented installation command does not specify a reviewed package version, integrity hash, lock file, or trusted package index. Different installations may therefore resolve to different releases. No evidence was found that the package name is intentionally malicious or typosquatted. The risk arises from non-reproducible dependency resolution and exposure to a compromised package repository, compromised future release, malicious index configuration, or dependency substitution in the installation environment. ### Attack Path 1. An operator follows the documented `pip install markdown` instruction. 2. Pip resolves the package using the environment's configured package index and selects the currently available compatible release. 3. If the index, package release, or local pip configuration has been compromised, attacker-controlled package code may be downloaded. 4. Package installation hooks or subsequently imported module code execute with the privileges of the account running the Skill. 5. The malicious dependency can access resources available to that account. ### Impact Assessment The potential privilege level equals that of the user or service account performing installation and running the renderer. In a compromised supply-chain scenario, impact could include arbitrary code execution, data access, credential theft, or modificat ...[truncated 254 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the dependency to a reviewed exact version. 2. Maintain dependencies in a lock file or fully pinned requirements file. 3. Require package hashes, for example through pip's `--require-hashes` mode. 4. Install packages only from an explicitly configured trusted index. 5. Verify package provenance and review release changes before upgrading. 6. Run dependency installation in an isolated environment with minimal privileges. 7. Add automated vulnerability and supply-chain scanning to the release process. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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 (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
声明描述的核心能力是“长文分页卡片生成器(文章→多张 PNG)”,意味着应具备文章内容切分、分页布局、连续生成多张图片等功能。但实际代码仅接收 line1/line2/line3 三行文本参数,填入 HTML 模板后由 Chrome 截图导出单个 PNG 文件。代码中没有任何文章解析、分页逻辑、批量输出、多页循环或多文件生成能力。模板选择、图标自动判断、词级高亮和单图截图都属于卡片渲染实现细节,但其主用途明显是单张海报/卡片生成,而非长文分页多图生成,因此描述与行为存在实质性不匹配。

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The primary skill description is written entirely in Chinese and presents the skill as operating in that language context, with no indication that users may choose another language or locale. Under the policy rule, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is clearly justified.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises shell and file-read capable behavior but does not declare any explicit tool scope such as permissions or allowed-tools. In practice, this can let an agent invoke broader capabilities than users or reviewers expect, especially since the workflow includes running a Python script and possibly fetching and rendering untrusted content.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger list contains broad natural-language phrases like '长文' and '做成卡片', which can cause the skill to activate in unintended contexts. Because the skill then uses shell/file capabilities and may fetch URLs or process user-supplied content, accidental invocation increases the chance of unnecessary code execution or handling of sensitive text.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
Lines L11-L12 explicitly instruct that the LLM must pre-calculate pagination and not depend on mechanical script splitting. However, lines L62-L66 describe script-side segmentation rules marked as requiring no LLM intervention, which directly contradicts the earlier guidance about where pagination responsibility resides.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file includes user-facing natural-language content in the module docstring and CLI help strings that assumes Chinese as the interaction language. The policy for this category flags forcing a specific language without user opt-in, and no alternative language or justification is provided here.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
f"--window-size={w},{h}",
        f"file://{tmp_html}",
    ]
    result = subprocess.run(cmd, capture_output=True)
    if result.returncode != 0:
        sys.exit(f"Chrome failed:\n{result.stderr.decode()}")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
f"--window-size={w},{h}",
        f"file://{tmp_html}",
    ]
    result = subprocess.run(cmd, capture_output=True)
    if result.returncode != 0:
        sys.exit(f"Chrome failed:\n{result.stderr.decode()}")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The file contains natural-language comments exclusively in Chinese (for example, labels for the clover parts), which constitutes a locale/language choice embedded in the asset without any indication of user opt-in or documented justification. Under the stated policy, forced language selection in natural-language content can be a policy violation even when it appears only in comments.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The natural-language comments and example footer/tip text are entirely Chinese, such as the stated purpose, parameter descriptions, and example labels. This suggests the template is designed around a fixed locale without indicating that users can choose another language or that the template is intentionally region-specific.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The template documentation and parameter descriptions are written in Chinese, while the rendered footer hard-codes an English phrase ('made by Jinx'). This indicates a fixed language choice in natural-language content without any user opt-in or configurable locale behavior.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
Lines L70-L72 specify default output footer text such as '公众号 · 早早集市' and '小红书 · 阿康', and line L72 adds a Chinese prompt for non-final pages. This imposes a specific language/locale in generated output without any user opt-in or alternative language option.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
This is a natural-language policy concern because the file presents usage instructions and operational messages in a single language by default, with no indication that users can opt into another locale. For organizations that require language choice or default-language neutrality, this can violate locale policy expectations.

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The docstring says templates are located relative to `skills/z-card-image/`, but the code computes `SKILL_DIR` from the current file's parent directory and uses that to resolve `assets/templates`. This is an active documentation/code mismatch, even though it appears operationally harmless.