Back to skill

Security audit

z-card-image

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent image-rendering tool, but it runs user-controlled content through unsandboxed local browser rendering and embeds some fixed third-party branding into outputs.

Review this skill before installing if you will render content from untrusted sources. It should be run in a contained workspace with network access limited, and outputs should be checked for unwanted branding such as 早早集市 or made by Jinx. Prefer explicit output paths and packaged image assets, and avoid feeding raw HTML or remote-resource Markdown into the article renderer.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T01 · Skill Instruction Hijacking

Error
Location
assets/templates/wechat-cover-split.html:130
Finding

Hard-Coded Third-Party Branding Overrides User-Controlled Output

Content
View full analysis
公众号·早早集市
{{MAIN_TEXT_LINE1}}
{{MAIN_TEXT_LINE2}}
made by Jinx
``` The corresponding reference explicitly documents that the caller-supplied footer is ignored: ```markdown | `--footer` | `made by Jinx` | Reserved parameter; the template actually always displays `made by Jinx` | ``` The skill also establishes third-party branding as the default: ```markdown | Platform | `--footer` | `--bg` | `--highlight` | | Official account (default) | `Official Account · Zaozao Market` | `#e6f5ef` | `#22a854` | ``` ### Technical Analysis The WeChat cover template embeds the names “早早集市” and “Jinx” directly into generated images rather than using the available `{{FOOTER_TEXT}}` placeholder. Although `render_card.py` accepts a `--footer` argument and performs a replacement for `{{FOOTER_TEXT}}`, that placeholder is not used for these visible fields. Consequently, changing `--footer` cannot remove or replace all third-party branding. The skill instructions also select branded defaults for ordinary rendering requests. This alters the user's requested artifact by adding persistent promotional content that is not technically necessary for image generation. This issue affects output integrity rather than host privileges. It is classified as skill instruction hijacking because the skill's instructions and templates redirect normal image-generation behavior toward producing branded artifacts. ### Attack Path 1. A user requests a WeChat article cover without requesting third-party branding. 2. `SKILL.m ...[truncated 785 chars]
Remediation
View remediation
{{EYEBROW_TEXT}}
{{FOOTER_TEXT}}
``` 2. Default branding and attribution fields to empty values. 3. Add third-party branding only when the user explicitly requests or consents to it. 4. Ensure that `--footer` consistently controls every visible attribution field. 5. Add regression tests that render a custom footer and verify that neither “早早集市” nor “Jinx” appears unless explicitly supplied. 6. Update `SKILL.md`, `README.md`, and `references/wechat-cover-split.md` so their documented behavior matches the implementation. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/render_article.py:128
Finding

Unsanitized Markdown HTML Is Executed by Unsandboxed Headless Chrome

Content
View full analysis
str: """Render the complete text as Markdown, supporting full Markdown syntax.""" try: import markdown as md_lib except ImportError: sys.exit('The markdown package must be installed: pip install markdown') return md_lib.markdown(text, extensions=['fenced_code', 'tables', 'nl2br']) ``` The generated HTML is inserted without sanitization: ```python def render_page(chrome, tpl, out_path, title, content_html, page_label, bottom_tip, highlight, bg, footer, icon_path, avatar_path, font_path, md_css_path=''): html = tpl 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, } for k, v in replacements.items(): html = html.replace(k, v) ``` The resulting document is rendered with Chrome's sandbox 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) ``` ### Technical Analysis Python Markdown permits raw HTML in Markdown input by default. The returned string is placed into `{{CONTENT_HTML}}` without escaping or sanitization. An attacker who controls article text can therefore introduce HTML elements that the browser interprets as active document content. Ex ...[truncated 1834 chars]
Remediation
View remediation
`, event-handler attributes, remote images, iframes, and malformed HTML. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/render_card.py:84
Finding

Unvalidated Style Values and Unescaped Resource Paths Permit Template Injection

Content
View full analysis
``` The same unsafe substitution pattern also appears in: - `scripts/render_article.py:146-161` - `scripts/render_x_like_posts.py:247-265` ### Technical Analysis User-controlled color values are inserted directly into stylesheet declarations without validation. A value containing CSS delimiters can terminate the intended declaration and add arbitrary CSS, including resource-loading constructs such as `url(...)`. User-controlled icon or avatar paths are inserted into quoted `src` attributes without HTML attribute escaping. A crafted value containing quotation marks can break out of the attribute and introduce additional attributes or markup. A URL supplied as an icon or avatar can also cause Chrome to access a remote resource during rendering. The issue is not shell-command injection because `subprocess.run` receives an argument ...[truncated 1107 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/render_card.py:26
Finding

Developer-Specific Absolute Asset Path Causes Unauthorized External File Access Attempts

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (24)

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/templates/x-like-posts.html (reported line 5)May include surrounding context.

html
<html>
<head>
<meta charset="UTF-8">
<!--
  Template: x-like-posts
  Width: 900px
  Height: dynamic

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/templates/x-like-posts.html (reported line 5)May include surrounding context.

html
<html>
<head>
<meta charset="UTF-8">
<!--
  Template: x-like-posts
  Width: 900px
  Height: dynamic

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill invokes shell commands for environment checks and directs the agent to read additional local reference files, but it does not declare an explicit tool scope such as allowed tools or permissions. That mismatch weakens isolation and review because an agent may use broader shell/file capabilities than the skill actually needs, increasing the chance of unintended command execution or file access during rendering workflows.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The instruction that any '帖子类型数据' intended for export as an X-style long image should route to x-like-posts is overly broad and can capture loosely related or malformed inputs. In a skill that reads reference files and may invoke render scripts, broad routing increases the risk of the wrong processing path being triggered, causing misuse of scripts, unexpected file handling, or unsafe parameter propagation from unvalidated input.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The scene-matching phrases for x-like-posts and related templates are semantically broad and overlap with common social-media content descriptions, making accidental or adversarial triggering easier. Because the skill then follows template-specific instructions and rendering flows, ambiguous dispatch can lead to incorrect script execution paths, improper argument construction, or unsafe handling of user-provided export paths.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template documentation and parameter descriptions are written in Chinese, and the font stack is tailored to Chinese display, indicating a locale-specific design. Because the file does not state that this template is only for Chinese-language output or offer any language/locale choice, it can violate a language policy that requires user opt-in or documented regional scope.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Lines L11-L12 state that the LLM must calculate pagination itself and should not rely on script-based splitting. However, lines L62-L66 later describe script-side pagination rules that explicitly perform splitting logic. This is an active contradiction in the file's documented intent about who is responsible for segmentation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The document states that the template currently displays time in "Asia/Shanghai (UTC+8)" as a fixed rule. This is a locale/timezone constraint that affects rendered output but does not offer user choice or clearly justify why this region-specific setting is required.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language instructions, help text, and runtime messages entirely in Chinese, which effectively forces a specific language for users. The file does not offer an opt-in language choice or explain that the skill is intentionally limited to a Chinese-speaking or region-specific context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring, usage instructions, and several help strings are written only in Chinese, which imposes a specific language on users without any opt-in or explanation that the skill is region-specific. Under the policy, forcing a locale or language without user choice is a natural-language policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_article.py (reported line 174)May include surrounding context.

python
f"--window-size={w},{window_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()}")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_card.py (reported line 148)May include surrounding context.

python
f"--window-size={w},{window_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()}")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/render_card.py (reported line 169)May include surrounding context.

python
"1",
            str(out),
        ]
        crop_result = subprocess.run(crop_cmd, capture_output=True)
        screenshot_path.unlink(missing_ok=True)
        if crop_result.returncode != 0:
            sys.exit(f"ffmpeg crop failed:\n{crop_result.stderr.decode()}")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The script launches Chrome/Chromium in headless mode with the --no-sandbox flag while rendering attacker-controlled content into a local HTML file. Although subprocess.run is used safely as an argument list rather than a shell string, the dangerous part is disabling the browser sandbox, which significantly increases risk if malicious post content, image paths, or HTML-triggered browser behavior reaches a vulnerable browser engine.

Content

Scanner excerpt · scripts/render_x_like_posts.py (reported line 286)May include surrounding context.

python
f"--screenshot={out}",
        f"file://{tmp_html}",
    ]
    result = subprocess.run(cmd, capture_output=True)
    Path(tmp_html).unlink(missing_ok=True)
    if result.returncode != 0:
        sys.exit(f"Chrome failed:\n{result.stderr.decode()}")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description is written as an instruction and product description entirely in Chinese, with no indication that other languages are supported or that the Chinese-only constraint is intentional and justified. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The file contains natural-language comments entirely in Chinese (for example, labels for the clover parts), which imposes a specific language in the asset metadata/comments without offering any language choice or documenting a locale-specific need. This matches the language/locale policy violation category because the natural-language content is fixed to one language with no opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The natural-language comments and example parameter values specify Chinese-only interface text such as the usage description and footer tip examples. This suggests the skill/template is designed to emit a fixed locale experience without documenting any user language choice or opt-in, which can violate language/locale policy requirements.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The natural-language comment on L009 uses Chinese exclusively to describe the template purpose. This creates a language-specific constraint in the file without offering a language choice or documenting why the locale is required, which conflicts with the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The natural-language comment uses Chinese ('用途', '帖子') and the template hardcodes a Chinese font fallback ('PingFang SC'), which signals a locale-specific design assumption. There is no accompanying note that the template is intended only for Chinese-language usage or that users can choose locale-specific variants.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This file consistently instructs use of Chinese text conventions, including Chinese character counting and punctuation-based splitting, but does not state that the template is limited to Chinese-language content or offer user opt-in for another locale. That can amount to a language/locale policy issue when a skill implicitly forces one language without explicit choice or justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The --icon parameter accepts an arbitrary filesystem path, and that path is injected into the rendered HTML as {{ICON_PATH}} without restriction to packaged assets. Because headless Chrome loads the local HTML file, an attacker who can control --icon may cause the process to read and embed arbitrary local files as image resources, creating a local file disclosure primitive and expanding access beyond the skill's asset directory.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest describes generating card/poster/cover images, but does not mention invoking local browser and media-processing executables. While this may be an implementation choice for rendering, spawning external programs is a materially broader capability than simple in-process image generation and is not justified explicitly by the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring is entirely in Chinese and directs users to another script, with no indication that language choice is optional or that the skill is intentionally region-specific. This can violate a language/locale policy when users are not given an opt-in or alternative locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script hard-codes Asia/Shanghai and the UTC+8 label for displayed timestamps, which imposes a specific locale/timezone on all rendered output. This is a natural-language policy concern because users are not offered any opt-in or override for locale-specific presentation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.