Back to skill

Security audit

Echarts Chart Skill

Security checks for vulnerabilities and agentic risk

Overview

This chart skill is mostly purpose-aligned, but its HTML export can embed untrusted chart text into executable browser script and should be reviewed before use.

Review before installing if you may render charts from untrusted or shared data. Avoid opening or hosting generated HTML previews from untrusted inputs until the renderer escapes inline JSON safely, and consider bundling or pinning ECharts locally instead of loading it from a CDN. Be aware that export commands write files to disk and may overwrite chosen output paths.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
src/core/render.ts:6
Finding

Arbitrary JavaScript Execution Through Unsafe Chart Option Embedding

Content
View full analysis

Vulnerability Details

File Location: src/core/render.ts:6-28
Vulnerability Type: Stored HTML and JavaScript injection
Risk Level: High

Vulnerable Code

ts
export function renderHtml(option: ChartOption, width: number, height: number): string {
  const optionJson = JSON.stringify(option, null, 2);
  return `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ECharts Preview</title>
    <script src="${CDN_URL}"></script>
    <style>
      html, body { margin: 0; padding: 0; background: #f3f5f7; font-family: "Segoe UI", sans-serif; }
      .wrap { padding: 24px; }
      #chart { width: ${width}px; height: ${height}px; margin: 0 auto; background: #fff; border-radius: 16px; box-shadow: 0 12px 40px rgba(15, 23, 42, 0.10); }
    </style>
  </head>
  <body>
    <div class="wrap">
      <div id="chart"></div>
    </div>
    <script>
      const chart = echarts.init(document.getElementById("chart"));
      const option = ${optionJson};
      chart.setOption(option);
    </script>
  </body>
</html>`;
}

The same vulnerable implementation is present in the distributed executable file at dist/core/render.js:2-25.

Technical Analysis

JSON.stringify() produces valid JSON but does not make the result safe for direct insertion into an HTML script element. In particular, an attacker-controlled string can contain the HTML parser terminator </script>.

Although such a sequence remains part of a JavaScript string from the JavaScript parser's perspective, the HTML parser processes the script element first and terminates it when it encounters </script>. The remaining attacker-controlled content can then introduce a new script element.

For example, an option property containing the following value can break out of the generated inline script:

json
{
  "t
...[truncated 1970 chars]
Remediation
View remediation

Remediation Suggestions

  1. Escape serialized JSON for safe placement inside an HTML script element. At minimum, encode HTML-significant characters and JavaScript line separators:

    ts
    function serializeForInlineScript(value: unknown): string {
      return JSON.stringify(value, null, 2)
        .replace(/&/g, "\\u0026")
        .replace(/</g, "\\u003c")
        .replace(/>/g, "\\u003e")
        .replace(/\u2028/g, "\\u2028")
        .replace(/\u2029/g, "\\u2029");
    }
    

    Then replace:

    ts
    const optionJson = JSON.stringify(option, null, 2);
    

    with:

    ts
    const optionJson = serializeForInlineScript(option);
    
  2. Prefer separating data from executable code. Place safely encoded JSON in a non-executable element and parse it from a fixed script:

    html
    <script id="chart-option" type="application/json">SAFE_JSON</script>
    

    Ensure <, &, and the script terminator cannot appear literally in that element before reading it with textContent and calling JSON.parse().

  3. Add runtime schema validation for chart options or accept a restricted option schema rather than trusting arbitrary parsed JSON.

  4. Add regression tests with payloads containing:

    text
    </script><script>alert(1)</script>
    

    Verify that the generated HTML contains no literal attacker-controlled closing script tag.

  5. Rebuild and commit dist/core/render.js after correcting the TypeScript source because users execute the distributed JavaScript implementation.

  6. Apply a restrictive Content Security Policy to hosted previews as defense in depth. Avoid allowing arbitrary inline scripts where possible.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (24)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · README.md (reported line 220)May include surrounding context.

md
> Use my category totals and generate a pie chart.

## Output Rules

- `--out` writes to an exact file path
- `--out-dir` writes to a directory using the default output filename

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Yes, this is a mismatch. The declared description promises substantial chart-related functionality, but the provided code chunk does not implement any observable behavior at all. It is effectively an empty module (export {}), so the actual behavior does not match the declared primary purpose.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · SKILL.md (reported line 40)May include surrounding context.

npm install

text

## Output rules

- `--out` writes to an exact file path.
- `--out-dir` writes the default file into a directory you choose.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 51)May include surrounding context.

md
node dist/cli/recommend-chart.js --input examples\study-progress.request.json

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

md
node dist/cli/generate-chart.js --input examples\study-progress.request.json

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

README 将“用我的数据生成一个饼图”作为代表性请求,但没有说明这是示例还是严格触发条件,也没有列出排除条件或更具体的调用范围。这类表述与日常对话高度重叠,容易让代理在普通数据讨论中也尝试调用该技能。

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The HTML renderer embeds a third-party script from jsDelivr, which introduces a network dependency and a software supply-chain risk outside the skill's apparent local rendering/export scope. If the CDN is unavailable, blocked, or serves compromised content, the generated preview HTML can fail or execute attacker-controlled JavaScript in the viewer's browser.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated HTML silently fetches executable JavaScript from a remote CDN without any user-facing notice. This creates privacy, reliability, and supply-chain exposure because opening the exported HTML causes outbound network access and trusts remote code execution in the browser.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file explains that the skill can export artifacts and write them to locations such as Desktop, home, or the current working directory. While file output is central to the skill's purpose, the README does not explicitly warn users that running the render/export flow will create or overwrite local files, which is a user-data/system-affecting behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code writes content to a filesystem path derived from CLI arguments or defaults, including creating parent directories, but it provides no confirmation prompt, log message, comment, or docstring disclosing that behavior. For a code-file review under SQP-2, file writes should have some visible disclosure unless clearly documented elsewhere, which is not 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 JSON file contains multiple user-facing strings in Chinese, such as the title, subtitle, and series labels, with no indication that the skill is region-specific or that users can opt into this locale. Per the policy, forcing a specific language without user choice can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest describes generating ECharts-based HTML or SVG previews, which implies a self-contained chart artifact. This example preview loads ECharts from a third-party CDN, so the produced HTML is not fully standalone and introduces external network dependency not reflected in the description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The HTML preview hard-codes Chinese text for the chart title, subtitle, and series labels while the document itself is otherwise generic and marked with lang="en". This creates a natural-language locale policy issue because the skill output is fixed to a specific language without offering user opt-in or explaining that the preview is intentionally 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

This SVG contains multiple visible text labels and titles in Chinese, including the data labels and chart title/subtitle. Because SQP-3 applies to all file types, hard-coding a specific language without offering user opt-in or documenting a justified regional constraint is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The HTML root declares lang="en", which fixes the experience to English. Under the policy, forcing a specific language without user opt-in or documented justification can be a natural-language locale violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This HTML file fetches resources from Google Fonts and jsDelivr, which causes the user's browser to make network requests to third parties. There is no visible notice, comment, or other disclosure in the file explaining that external network access occurs when the demo is opened.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: echarts==5.6.0 — 1 advisory(ies): CVE-2026-45249 (Apache ECharts has a cross-site scripting (XSS) vulnerability)

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The lockfile pins Apache ECharts 5.6.0, and the reported advisory indicates a cross-site scripting vulnerability. This skill explicitly generates embeddable HTML/SVG chart output, so if untrusted data or labels are rendered into charts, the dependency context makes the XSS issue more relevant than it would be in a purely server-side-only package.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: esbuild==0.27.3 — 1 advisory(ies): GHSA-g7r4-m6w7-qqqr (esbuild allows arbitrary file read when running the development server on Window)

Low
Category
Supply Chain
Confidence
83% confidence
Finding

The lockfile includes esbuild 0.27.3, and the advisory describes arbitrary file read exposure when running the esbuild development server on Windows. In this skill, esbuild is only a dev dependency pulled in via tsx, which makes exploitation less likely in production, but it is still a real supply-chain risk for developers if a Windows dev server workflow is used.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 15)May include surrounding context.

json
"test": "npm run check && npm run build"
  },
  "dependencies": {
    "echarts": "^5.5.0"
  },
  "devDependencies": {
    "@types/node": "^22.13.14",

Known Vulnerable Dependency: echarts==5.6.0 — 1 advisory(ies): CVE-2026-45249 (Apache ECharts has a cross-site scripting (XSS) vulnerability)

Low
Category
Supply Chain
Confidence
83% confidence
Finding

The manifest allows installation of echarts 5.6.0 via the ^5.5.0 range, and the cited advisory indicates an XSS issue in that version. In the context of a chart-generation skill that exports embeddable HTML/SVG, an XSS flaw in the charting library is more relevant because rendered output may be opened in a browser or embedded into other pages.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 18)May include surrounding context.

json
"echarts": "^5.5.0"
  },
  "devDependencies": {
    "@types/node": "^22.13.14",
    "typescript": "^5.8.2"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 19)May include surrounding context.

json
},
  "devDependencies": {
    "@types/node": "^22.13.14",
    "typescript": "^5.8.2"
  }
}

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This code creates directories and writes content to a resolved output path, but it provides no confirmation prompt, user-facing log/print, or inline comment/docstring disclosing that a filesystem write will occur. For a reusable CLI helper, that omission can make side effects less visible to users invoking downstream commands.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The file emits <html lang="en">, which forces an English locale marker in generated output. Under the policy, locale-specific behavior should not be forced without user opt-in or a documented justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.