Back to skill

Security audit

Info Card

Security checks for vulnerabilities and agentic risk

Overview

This card generator is mostly coherent, but it renders unescaped user data in an active browser and can make under-disclosed network requests.

Install only if you plan to render card data you trust. Avoid processing JSON supplied by untrusted parties, avoid remote or internal image URLs, and run generation in an isolated environment with restricted network access when content is sensitive. Pin Playwright/Chromium versions for reproducible installs.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_card.py:691
Finding

Unescaped User Input Allows Active HTML and JavaScript Execution

Content
View full analysis
{desc}' if desc else "" items_html += f"""
{i:02d}
{title}
{desc_html}
""" return tpl.safe_substitute( bg_color=data.get("bg_color", "#F5F0E8"), accent_color=data.get("accent_color", "#8B6F47"), brand_color=data.get("brand_color", "#5C4A35"), title_color=data.get("title_color", "#1A1209"), text_secondary=data.get("text_secondary", "#6B5D4F"), text_muted=data.get("text_muted", "#A89880"), divider_color=data.get("divider_color", "#D4C4B0"), num_bg=data.get("num_bg", "#D4C4B0"), num_color=data.get("num_color", "#5C4A35"), accent_circle1=data.get("accent_circle1", "#C4A882"), accent_circle2=data.get("accent_circle2", "#8B6F47"), brand=data.get("brand", "BRAND"), issue_no=data.get("issue_no", "Vol.01"), kicker=data.get("kicker", ""), title=data.get("title", "标题").replace("\n", "
"), subtitle=data.get("subtitle", ""), list_label=data.get("list_label", "核心要点"), list_items_html=items_html, footer_brand=data.get("footer_brand", data.get("brand", "BRAND")), footer_tagline=data.get("footer_tagline", ""), ) ``` The generated document is subsequently loaded into an active Chromium page: ```python with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.ne ...[truncated 2931 chars]
Remediation
View remediation
")` before escaping. Escape first and then add the controlled line-break markup: ```python safe_title = "
".join( escape(part, quote=True) for part in str(raw_title).splitlines() ) ``` 3. Apply context-specific validation: - Escape HTML text and attribute values. - Restrict class names to explicit allowlists. - Parse and validate colors rather than inserting arbitrary CSS. - Reject unsupported URL schemes. - Do not use one generic sanitizer for HTML, CSS, and URL contexts. 4. Avoid supporting arbitrary raw HTML. If limited formatting is a product requirement, use a mature allowlist sanitizer and permit only necessary formatting elements without event handlers, scripts, frames, forms, or active URLs. 5. Disable JavaScript during screenshot generation if the templates do not require it: ```python browser = p.chromium.launch(headless=True, java_script_enabled=False) ``` Alternatively, set `java_script_enabled=False` on the browser context where supported. 6. Add Playwright request interception and reject all network traffic unless a resource has been explicitly approved. 7. Add regression tests covering script elements, event-handler attributes, malformed tags, attribute breakouts, CSS breakouts, iframes, and remote resource elements. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_card.py:867
Finding

Unrestricted Image URLs Permit Browser-Based SSRF and Network Tracking

Content
View full analysis
product """ ``` The profile-card renderer follows the same pattern: ```python avatar_url = data.get("avatar_url", "") avatar_emoji = data.get("avatar_emoji", "👤") if avatar_url: avatar_html = f'avatar' else: avatar_html = avatar_emoji ``` Chromium loads the generated resources without request filtering: ```python page.set_content(html_content, wait_until="networkidle") ``` ### Technical Analysis The `image_url` and `avatar_url` fields are accepted without validation of: - URL scheme. - Destination hostname. - Resolved IP address. - Redirect targets. - Port. - Response size. - Response time. - Content type. When Chromium parses the generated image elements, it sends requests to the supplied destinations. Browser same-origin rules may restrict the ability of injected JavaScript to read some response bodies, but they do not generally prevent an image request from being transmitted. Therefore, the renderer can be used as a request-delivery mechanism to localhost, private networks, link-local services, or attacker-controlled tracking endpoints. Because the values are also not attribute-escaped, this finding can be combined with the active HTML injection finding by breaking out of the `src` attribute. ### Attack Path 1. An attacker supplies a product-feature or profile-card data object with an internal or attacker-controlled UR ...[truncated 1351 chars]
Remediation
View remediation

other

Note
Location
assets/templates/night-essay.html:8
Finding

Night-Essay Template Makes an Undisclosed Request to Google Fonts

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding

Playwright and Chromium Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
" python3 -m playwright install chromium ``` 2. Maintain a dependency lock file containing cryptographic hashes, using a tool such as `pip-compile --generate-hashes`. 3. Pin and document the expected Chromium revision associated with the selected Playwright release. 4. Install dependencies in an isolated virtual environment rather than the global Python environment. 5. Use an internally reviewed package mirror or trusted artifact repository in controlled deployments. 6. Run dependency vulnerability and provenance checks during release preparation. 7. Prefer a prebuilt, digest-pinned container image containing the reviewed Playwright and Chromium versions when reproducibility is important. 8. Update the script's error message to reference the exact pinned installation process rather than recommending an unconstrained latest release. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (29)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill documentation indicates code-assisted behavior that reads input data files and writes output PNG files, but it does not declare any tool scope such as permissions or allowed-tools. Missing scope declarations can cause the agent platform to grant broader-than-necessary file access or make the access model ambiguous, violating least privilege and increasing the blast radius if the skill is abused or mis-invoked.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The natural-language description and branding strongly present the skill as generating “小红书风格” content and all usage guidance is written in Chinese, without stating that users may choose another language or locale. That can be a locale policy concern when the skill implicitly defaults to a specific language/cultural format without explicit opt-in.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrases include very generic terms like 'card', '海报', '生成卡片', and '做一张图', which are likely to match ordinary conversation unrelated to this skill. Overbroad activation can cause the wrong skill to run unexpectedly, leading to unintended file operations or content generation in contexts where the user did not intend to invoke it.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The template hard-codes lang="zh", which imposes a specific language/locale on all rendered output. Under the policy, locale constraints should either offer user opt-in/choice or be clearly documented as a justified region-specific requirement, neither of which is present in this file.

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", which forces a specific language/locale in the rendered output. Under the policy rules, locale constraints should either be user-selectable or clearly documented as intentionally region-specific, neither of which is evident in this file.

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", which hard-codes a Chinese language/locale for rendered output. Under the policy, forcing a specific language without user opt-in or clear region-specific justification 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", which hard-codes the output language/locale to Chinese. Under the stated policy, forcing a specific language without user opt-in or a documented region-specific reason 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 template hard-codes lang="zh", which imposes a specific language/locale on all rendered output. This is a natural-language policy concern because the file provides no opt-in, fallback, or documentation that the template is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The template hard-codes lang="zh", which imposes a specific language/locale on all rendered output. Under the policy rules, a fixed locale is a natural-language policy violation when there is no user opt-in or documented region-specific justification in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The template hard-codes lang="zh", which enforces a specific language/locale in all rendered output. Under the policy rules, this is a natural-language locale constraint without any visible opt-in or justification that the template is intended only for a Chinese-specific context.

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", which forces the rendered content to be treated as Chinese. Under the policy, locale constraints should either be user-selectable or clearly documented as justified for a region-specific tool; this file provides neither.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

User-controlled fields such as image_url and avatar_url are inserted directly into HTML tags, and Playwright loads the page with wait_until="networkidle". That causes the renderer to fetch attacker-supplied remote URLs, which can leak the host's IP/network metadata, enable unintended outbound requests, and potentially reach internal-only endpoints if this tool runs in a trusted environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

In --html-only mode, the script writes rendered HTML content derived from user-supplied JSON to a file under /tmp, but there is no comment, docstring warning, or runtime disclosure highlighting that content will be persisted to disk. Because the tool otherwise presents itself as an image generator, users may not expect their provided content to be saved as a separate HTML artifact.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This HTML template sets lang="zh" on the document root, which hard-codes a specific language/locale. The policy for natural-language violations says to flag files that force a specific language without user opt-in, and this file provides no alternative or explanation that it is region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document sets lang="zh" on the root HTML element, which hard-codes a specific language/locale. Under the policy, locale-specific behavior should either be user-selectable or clearly justified as region-specific; neither is evident in this file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This HTML template sets lang="zh" at L002, which hard-codes a specific language/locale for all rendered output. Under the policy, forcing a language without user opt-in or clear region-specific justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The document declares lang="zh", which hard-codes a specific language/locale for the rendered skill output. Under the policy, locale constraints should be user-selectable or clearly justified as region-specific, neither of which is evident in this file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The HTML root sets lang="zh", which hard-codes a Chinese language/locale for all rendered output. Per the policy, forcing a specific language without offering user choice or documenting a justified region-specific constraint is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template hard-codes lang="zh", which enforces a specific language/locale in the generated output. Under the policy, locale constraints should be optional, user-selected, or clearly justified as region-specific; this file provides neither.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template sets lang="zh", which hard-codes a specific language/locale in a natural-language-facing asset. The file does not indicate that this is optional, user-selected, or justified as a region-specific template, so it may violate locale-choice policy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document sets lang="zh", which hard-codes a Chinese language/locale for all rendered output. This is a natural-language policy concern because the template does not offer user opt-in or indicate that the skill is intentionally region-specific.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The template imports Google Fonts from an external origin, which causes network access during rendering and leaks metadata such as IP, timing, and possibly document-generation context to a third party. In a card-generation skill that should be able to render locally and deterministically, this expands the trust boundary and can break in restricted or offline environments.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document sets lang="zh", which hard-codes a specific language/locale in the template. Under the policy, forcing a locale without user opt-in or clear justification 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
95% confidence
Finding

The template sets the document language to "zh" via the html lang attribute, which enforces a specific locale choice in natural-language metadata. The file does not offer a user opt-in or indicate that this is a region-specific or otherwise justified constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file declares lang="zh" on the root <html> element, which hard-codes a specific language/locale choice. Under the policy, forcing a language without offering a user choice or documenting a justified regional constraint is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.