Back to skill

Security audit

Info Visualize

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent chart/report generator, but its HTML/SVG output can include unescaped input data, creating a script-injection risk when rendering untrusted data.

Install only if you will render trusted data or review/sanitize JSON before generating HTML charts. Be careful publishing generated HTML/SVG from untrusted inputs, prefer PNG output for untrusted data, pin Pillow in a virtual environment, and use --archive only for reports you intentionally want copied to another directory.

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

Note
Location
scripts/svg_bar_chart.py:242
Finding
Unavoidable Third-Party Branding in Generated Artifacts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/svg_bar_chart.py:242-246`; `scripts/png_longform.py:385-388`; documented in `SKILL.md:158-161` **Vulnerability Type**: Persistent output manipulation **Risk Level**: Low ### Complete Code Snippets From `scripts/svg_bar_chart.py:242-246`: ```python <rect y="{chart_bottom+24}" width="{W}" height="{FOOTER_H}" fill="{theme['bg_alt']}"/> <text x="{W//2}" y="{chart_bottom+24+28}" font-size="11" fill="{theme['text_muted']}" font-family="Microsoft YaHei,sans-serif" text-anchor="middle">{footer}</text> <text x="{W//2}" y="{chart_bottom+24+46}" font-size="10" fill="#2A3A50" font-family="Microsoft YaHei,sans-serif" text-anchor="middle">Powered by WorkBuddy</text> ``` From `scripts/png_longform.py:385-388`: ```python # WorkBuddy watermark wm = "Powered by WorkBuddy" wm_w = draw_obj.textbbox((0, 0), wm, font=F_SMALL)[2] draw_obj.text((self.W - wm_w - PAD, y0 + 22), wm, font=F_SMALL, fill=(38, 58, 82)) ``` ### Technical Analysis Both renderers unconditionally add the fixed text `Powered by WorkBuddy` to generated artifacts. The Skill presents itself as a general visualization utility, but it provides no documented or implemented option to disable or replace this attribution. This behavior modifies user-requested output with unrelated fixed branding. It does not grant code execution or system privileges, but it can affect the integrity and provenance of reports intended for publication. ### Attack Path 1. A user loads the Skill and requests an SVG/HTML chart or PNG report. 2. The relevant renderer processes the supplied report data. 3. The renderer unconditionally inserts the WorkBuddy watermark. 4. The user publishes or distributes the artifact without realizing that third-party branding was embedded. ### Impact Assessment No operating-system privileges, credentials, or data-access capabilities are obtained. The impact is limited t ...[truncated 157 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the hard-coded watermark from both rendering implementations. - If attribution is required, expose an explicit configuration option such as: ```python config = { "branding_enabled": False, "branding_text": "" } ``` - Make branding disabled by default or clearly disclose it before rendering. - Ensure the caller can replace or omit attribution without editing source code. - Add tests verifying that generic output does not contain unexpected branding when branding is disabled. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/svg_bar_chart.py:130
Finding
Stored HTML and SVG Injection Through Unescaped Chart Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/svg_bar_chart.py:130-135`, `scripts/svg_bar_chart.py:160-170`, `scripts/svg_bar_chart.py:177-180`, `scripts/svg_bar_chart.py:196-197`, `scripts/svg_bar_chart.py:217-218`, `scripts/svg_bar_chart.py:242-253` **Vulnerability Type**: Stored HTML/SVG injection **Risk Level**: High ### Complete Code Snippets KPI values and labels are inserted directly into SVG text nodes at `scripts/svg_bar_chart.py:130-135`: ```python kpi_svg += f""" <rect x="{cx}" y="82" width="{card_w}" height="58" rx="8" fill="{theme['kpi_fill']}" stroke="{theme['accent']}" stroke-width="0.8" stroke-opacity="0.4"/> <text x="{cx + card_w//2}" y="108" font-size="22" font-weight="bold" fill="{theme['accent2']}" font-family="Microsoft YaHei,sans-serif" text-anchor="middle">{kpi['value']}</text> <text x="{cx + card_w//2}" y="128" font-size="11" fill="{theme['text_label']}" font-family="Microsoft YaHei,sans-serif" text-anchor="middle">{kpi['label']}</text>""" ``` Item labels, tooltips, and tags are inserted without escaping at `scripts/svg_bar_chart.py:160-170`: ```python rows_svg.append(f""" <rect x="0" y="{y}" width="{W}" height="{ROW_H}" fill="{bg}"/> <text x="{PAD}" y="{y+20}" font-size="12" fill="{theme['text_primary']}" font-family="Microsoft YaHei,sans-serif">{i+1:02d}. {label}</text> <rect x="{BAR_LEFT}" y="{y+6}" width="{bar_w:.1f}" height="18" rx="3" fill="{color}" opacity="0.9"> <title>{tooltip}</title> </rect> <text x="{LABEL_X}" y="{y+20}" font-size="12" fill="{color}" font-weight="bold" font-family="Microsoft YaHei,sans-serif">{display_val}</text> <text x="{W-PAD}" y="{y+20}" font-size="10" fill="{theme['text_muted']}" font-family="Microsoft YaHei,sans-serif" text-anchor="end">{tag}</text>""") ``` The chart title, footer, and HTML document title are also interpolated directly at `scripts/svg_bar_chart.py:217-218`, `242-253` ...[truncated 3079 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Escape every untrusted value before inserting it into HTML or SVG text contexts: ```python from html import escape safe_title = escape(str(title), quote=True) safe_label = escape(str(label), quote=True) safe_tooltip = escape(str(tooltip), quote=True) safe_footer = escape(str(footer), quote=True) ``` - Apply escaping consistently to titles, subtitles, labels, tags, extra fields, KPI fields, footer text, reference labels, and suffixes. - Do not use generic text escaping for values placed in attributes. Validate attribute values against strict allowlists. - Validate colors using a narrow pattern such as `#[0-9A-Fa-f]{6}` rather than accepting arbitrary attribute content. - Require finite numeric values for dimensions, chart values, maximum values, and reference-line positions. - Prefer constructing SVG through a safe XML library rather than assembling markup through f-strings. - Consider adding a restrictive Content Security Policy to generated HTML as defense in depth: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:"> ``` - Add regression tests using payloads containing `<script>`, closing SVG tags, event-handler attributes, ampersands, quotes, and malformed XML. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:22
Finding
Unpinned Pillow Dependency in Installation Guidance<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:22-27`; `scripts/png_longform.py:5-8`; `scripts/png_longform.py:65-69` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Complete Code Snippets The dependency table in `SKILL.md:22-27` instructs users to install Pillow without a version constraint: ```markdown | Script | Output format | Applicable scenario | Dependency | |------|---------|---------|------| | `svg_bar_chart.py` | SVG + HTML | Rankings, comparisons, and bar charts | None, standard library only | | `png_longform.py` | PNG long image | Daily reports, monitoring reports, and infographics | `pip install Pillow` | ``` The source repeats the unpinned installation command at `scripts/png_longform.py:5-8`: ```python """ png_longform.py — General-purpose dark-theme PNG long-image renderer info-visualize skill core script Dependency: pip install Pillow ``` The import error handler repeats the same instruction at `scripts/png_longform.py:65-69`: ```python try: from PIL import Image, ImageDraw, ImageFont except ImportError: print("ERROR: Please install Pillow first: pip install Pillow") raise ``` ### Technical Analysis The project instructs users to install the latest version of Pillow resolved by the configured Python package index. No exact version, lock file, package hash, or reviewed version range is supplied. This is not evidence that Pillow itself is malicious. The risk is that installations are not reproducible and may resolve to future releases with incompatible behavior or newly introduced vulnerabilities. Security also depends on the integrity of the user's configured package index and package-resolution environment. The script does not automatically install Pillow; exploitation requires a user to follow the documented installation command. ### Attack Path 1. A user attempts to run the PNG renderer without Pillow installed. 2. The documentation or error message instructs the user ...[truncated 725 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin Pillow to a reviewed release in a dependency file: ```text Pillow==<reviewed-version> ``` - Generate and verify cryptographic hashes, for example through a hash-locked requirements file: ```bash pip install --require-hashes -r requirements.txt ``` - Commit the dependency manifest or lock file to the project. - Use a trusted package index and avoid unreviewed mirrors. - Regularly update the pinned version after vulnerability review and compatibility testing. - Update `SKILL.md` and the import error message to direct users to the project dependency file rather than an unconstrained installation command. - Run the renderer in an isolated virtual environment with only the permissions required to read its input and write its output. ]]>
Vulnerability Patterns
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill documents capabilities that read input files and write output files, but it does not declare any explicit tool scope or permissions boundaries. This can lead to overbroad execution in an agent environment, where the skill may access or modify files without clear policy enforcement or user awareness.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger phrases are broad and match many ordinary requests such as 'make chart' or 'visualize data', which can cause the skill to activate in contexts the user did not intend. Overbroad activation is risky because the skill performs file generation and may write outputs automatically once selected by the agent.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation normalizes writing report files and archiving copies without warning the user about filesystem side effects. In an autonomous agent setting, undisclosed persistence can leak sensitive data into local storage or retained directories and make cleanup difficult.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
The natural-language description and examples are presented as a Chinese-only workflow, and the skill positions itself as a general visualization skill rather than a clearly region-specific tool. There is no statement that output language is user-selectable or that Chinese is merely the default.

Description-Behavior Mismatch

Low
Confidence
87% confidence
Finding
The skill includes an archive-copy behavior to a user-specific memory/news directory that goes beyond simple visualization output. Even if the behavior is convenience-oriented, extra persistence outside the immediate output path increases data exposure and can surprise users by storing generated content in secondary locations.

Context-Inappropriate Capability

Low
Confidence
81% confidence
Finding
The manifest describes rendering structured data into charts and long-form PNG reports. The optional `--archive` flow creates directories and copies the generated PNG into an arbitrary archive location, which is a file-management capability not necessary to perform visualization itself.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The generated document hard-codes `lang="zh-CN"`, which imposes a specific language/locale choice in output regardless of user preference. This is a natural-language policy concern because the skill does not offer any language or locale selection or document a justified region-specific constraint.

Static analysis

No suspicious patterns detected.