Back to skill

Security audit

Excel2Insights

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent spreadsheet analysis tool, but it has real unsafe handling of dataset-controlled names that can write chart files outside the intended folder and inject HTML into generated reports.

Review this skill before installing. Use it only on datasets and output folders you trust, avoid running it on attacker-supplied spreadsheets until filenames are sanitized and report HTML is escaped, and treat generated previews/reports as potentially containing sensitive source data.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/chart-generator.py:111
Finding
Path Traversal Through Dataset-Controlled Chart Filenames<![CDATA[ ## Vulnerability Details **File Location**: `scripts/chart-generator.py:111`, `scripts/chart-generator.py:145`, `scripts/chart-generator.py:179`, and `scripts/chart-generator.py:221` **Vulnerability Type**: Path traversal and uncontrolled file write **Risk Level**: Medium ### Vulnerable Code ```python # scripts/chart-generator.py:111 path = Path(out) / f"{col}_histogram.png" ``` ```python # scripts/chart-generator.py:145 path = Path(out) / f"{col}_bar.png" ``` ```python # scripts/chart-generator.py:179 path = Path(out) / f"{col}_pie.png" ``` ```python # scripts/chart-generator.py:221 path = Path(out) / f"scatter_{x_col}_vs_{y_col}.png" ``` ### Technical Analysis Column names from an input CSV, TSV, or spreadsheet are incorporated directly into chart filenames. The code does not sanitize path separators, reject absolute paths, generate opaque filenames, or verify that the resolved destination remains inside the configured output directory. A malicious column name containing path traversal components such as `../` can cause `matplotlib` to save a generated PNG outside the intended chart directory. Depending on the constructed name and operating system path semantics, absolute or nested path components may also redirect the output. The write remains constrained by the chart-specific suffix, such as `_histogram.png`, and the generated content is a PNG image. Nevertheless, an attacker can overwrite a matching file or create files in unintended directories writable by the process. ### Attack Path 1. An attacker supplies a CSV or spreadsheet with a numeric or categorical column name containing traversal components, such as `../../shared/target`. 2. A user or Agent runs `chart-generator.py` or `auto-pipeline.py` against that dataset. 3. The malicious column is selected for histogram, bar, pie, or scatter generation. 4. The filename expression preserves the traversal components. 5. `fig.savefig()` resolves the resulting path outside the intended char ...[truncated 721 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Convert every dataset-derived column name into a safe filename component: ```python import re import hashlib def safe_filename_component(value): text = str(value) sanitized = re.sub(r"[^A-Za-z0-9._-]+", "_", text).strip("._") digest = hashlib.sha256(text.encode("utf-8")).hexdigest()[:10] return f"{sanitized[:50] or 'column'}_{digest}" ``` 2. Resolve and validate every destination before writing: ```python def confined_output_path(output_dir, filename): base = Path(output_dir).resolve() destination = (base / filename).resolve() if destination.parent != base: raise ValueError("Chart destination escapes the output directory") return destination ``` 3. Use the sanitized component at every affected sink: ```python component = safe_filename_component(col) path = confined_output_path(out, f"{component}_histogram.png") ``` 4. Apply equivalent protection to histogram, bar, pie, and scatter filenames. 5. Reject column-derived names containing path separators or control characters as defense in depth. 6. Add regression tests using column names containing `../`, `..\`, absolute paths, Unicode separators, quotes, and very long strings. 7. Consider using generated identifiers for filenames and retaining the original column name only as escaped chart metadata. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/report-generator.py:121
Finding
Stored HTML Injection Through Unescaped Dataset Column Names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/report-generator.py:121-123` **Vulnerability Type**: Stored HTML and script injection **Risk Level**: Medium ### Vulnerable Code ```python if num_cols: html += f"<tr><td>Numeric</td><td>{len(num_cols)}</td><td>{', '.join(num_cols[:10])}{'...' if len(num_cols) > 10 else ''}</td></tr>" if cat_cols: html += f"<tr><td>Categorical</td><td>{len(cat_cols)}</td><td>{', '.join(cat_cols[:10])}{'...' if len(cat_cols) > 10 else ''}</td></tr>" ``` ### Technical Analysis CSV and spreadsheet column names are attacker-controllable data. The report generator concatenates these names directly into an HTML document without context-appropriate escaping. A column name containing HTML markup can terminate the existing table cell and insert new elements. A payload containing a `<script>` element or an event-handler attribute may execute when a user opens the generated report in a browser. The report does not define a Content Security Policy that would mitigate inline script execution. Although `pandas.DataFrame.to_html()` escapes values by default, the separately generated column-type rows shown above bypass that protection. ### Attack Path 1. An attacker creates a CSV or spreadsheet with a column name such as: ```html </td></tr><script>/* attacker-controlled JavaScript */</script><tr><td> ``` 2. A user or Agent runs `report-generator.py` or the automatic pipeline on the file. 3. The malicious name is classified as a numeric or categorical column. 4. The report generator interpolates the name into the HTML table without escaping. 5. The payload is persisted in the generated report. 6. When the report is opened in a browser, the injected markup is parsed and browser-permitted JavaScript may execute. ### Impact Assessment The injected code executes in the security context assigned by the browser to the generated local report. Depending on browser policy and how the report is hosted or distributed, it may: ...[truncated 487 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape all dataset-derived values before inserting them into HTML: ```python from html import escape def escaped_column_list(columns): return ", ".join(escape(str(column), quote=True) for column in columns) ``` ```python if num_cols: names = escaped_column_list(num_cols[:10]) suffix = "..." if len(num_cols) > 10 else "" html += ( f"<tr><td>Numeric</td><td>{len(num_cols)}</td>" f"<td>{names}{suffix}</td></tr>" ) ``` 2. Apply escaping to categorical column names and every other dynamic HTML value, including chart paths and alternative text. 3. Prefer a template engine with automatic HTML escaping rather than manual string concatenation. 4. Add a restrictive Content Security Policy, for example: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'"> ``` 5. Avoid allowing inline JavaScript in generated reports. 6. Add tests with column names containing `<script>`, event handlers, quotes, angle brackets, ampersands, and malformed HTML. 7. If reports may be hosted, serve them from an isolated origin with appropriate response headers such as `Content-Security-Policy` and `X-Content-Type-Options: nosniff`. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (23)

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The document declares `lang="zh-CN"`, which fixes the content locale to Simplified Chinese. Under the policy, locale-specific behavior should either provide user opt-in/choice or clearly justify that the skill is region-specific; this file does neither.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The example invocation phrases are very broad natural-language requests such as '帮我分析这份销售数据' and '对数据做个完整的统计分析并出报告', which can overlap with ordinary user prompts in a coding assistant. In an agent setting, that increases the chance of unintentional skill activation and automatic execution of local scripts against files in the workspace, especially because the walkthrough says the agent will automatically orchestrate the pipeline from SKILL.md instructions.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_script(script_path, args_list):
    cmd = [sys.executable, str(script_path)] + args_list
    result = subprocess.run(cmd, capture_output=True, text=True, cwd=Path(script_path).parent.parent)
    if result.returncode != 0:
        return {"error": result.stderr}
    try:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script can write a JSON report containing raw categorical values, cross-tab labels, sheet-derived content, and other dataset-derived details directly to an arbitrary output path without any privacy warning, redaction, or opt-in protection. In a data-analysis skill, datasets often contain sensitive business or personal information, so persisting these results to disk can unintentionally expose confidential data to other users, logs, backups, or downstream tooling.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script reads arbitrary spreadsheet/CSV content and emits head/tail preview rows directly to JSON output, which can expose sensitive data such as PII, credentials, financial records, or proprietary business information. In a file-inspection skill, automatic content preview increases disclosure risk because users may run it on untrusted or confidential datasets without realizing sample rows will be echoed in logs, agent transcripts, or downstream systems.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The HTML template sets the document language to "zh-CN", forcing a specific locale for every generated report. There is no user opt-in, configuration option, or documented region-specific justification for this language setting.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The script creates the output directory and writes a full HTML report containing dataset statistics, column names, and chart references to a file. Although file output is core functionality, there is no user-facing disclosure in code comments, help text, or printed messaging that the generated report may persist potentially sensitive data to disk.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The natural-language instructions and descriptions in the skill documentation are presented only in Chinese, which effectively forces a specific language on users without opt-in. The file does not indicate that the skill is region-specific or provide an alternative language option.

Missing User Warnings

Low
Confidence
84% confidence
Finding
This markdown file describes analyzing spreadsheet/CSV data and producing charts and structured insight reports, which can surface user data contents into generated artifacts. There is no warning that sensitive data may be included in previews, visualizations, or reports, so users are not alerted to privacy implications before using the skill.

Missing User Warnings

Low
Confidence
92% confidence
Finding
The skill explicitly documents that reports, charts, and other artifacts are written under an output directory, but it does not clearly warn users that running the pipeline creates multiple files on disk. In an agent setting, silent filesystem writes can surprise users, overwrite existing artifacts, persist sensitive data extracted from spreadsheets, or violate expectations for read-only inspection workflows.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The package description presents the skill entirely in Chinese, which can impose a language constraint on users without any indication that alternative languages are supported. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The walkthrough describes a one-click pipeline and shows generated artifacts under output/, but does not clearly warn that running the pipeline creates directories and writes multiple files. In an agent environment, users may interpret the request as read-only analysis, so silent filesystem writes can surprise users, overwrite prior artifacts, or leak data into generated reports and charts.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
numpy>=1.24.0
openpyxl>=3.1.0
matplotlib>=3.7.0
Confidence
92% confidence
Finding
The dependency is specified with a lower-bound version only, which allows different future versions to be installed over time. This weakens reproducibility and can expose deployments to newly introduced vulnerable or malicious upstream releases through supply-chain drift.

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
82% confidence
Finding
Pandas has known advisories in some versions, and because the manifest does not pin an exact release, it is impossible to verify whether an affected version will be installed. This does not prove a vulnerable version is present, but it is a real security weakness because version ambiguity prevents reliable risk assessment and can allow unsafe versions into deployments.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
numpy>=1.24.0
openpyxl>=3.1.0
matplotlib>=3.7.0
seaborn>=0.12.0
Confidence
92% confidence
Finding
The numpy requirement is unpinned and permits installation of any version at or above the minimum. That increases supply-chain risk and makes builds non-reproducible, which can result in unreviewed versions being deployed.

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
85% confidence
Finding
NumPy has multiple historical advisories, and the unpinned requirement means consumers may resolve to versions with different security characteristics. The main danger here is unverifiable and potentially unsafe dependency resolution rather than confirmed exploitation in this file.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
numpy>=1.24.0
openpyxl>=3.1.0
matplotlib>=3.7.0
seaborn>=0.12.0
tabulate>=0.9.0
Confidence
92% confidence
Finding
Using openpyxl>=3.1.0 allows future versions to be resolved without explicit review. In a skill that likely processes spreadsheet data, this creates avoidable supply-chain uncertainty and could expose consumers to vulnerable releases if upstream issues emerge.

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding
Openpyxl has had XML-related security issues, and this skill's dependency set suggests spreadsheet processing where openpyxl may be directly used on untrusted workbook data. Because the version is not pinned, affected releases cannot be ruled out, making this somewhat more concerning in context than a generic library advisory.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
numpy>=1.24.0
openpyxl>=3.1.0
matplotlib>=3.7.0
seaborn>=0.12.0
tabulate>=0.9.0
Confidence
90% confidence
Finding
The matplotlib dependency is not pinned to a specific version, so installations may vary by time and environment. This is a common dependency hygiene issue that increases supply-chain and reproducibility risk, even if no direct exploit is evident in the file itself.

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy>=1.24.0
openpyxl>=3.1.0
matplotlib>=3.7.0
seaborn>=0.12.0
tabulate>=0.9.0
Confidence
90% confidence
Finding
The seaborn package is declared with a broad lower-bound rather than an exact version. That permits uncontrolled upgrades and can introduce vulnerable or incompatible releases into environments using this skill.

Unpinned Dependencies

Low
Category
Supply Chain
Content
openpyxl>=3.1.0
matplotlib>=3.7.0
seaborn>=0.12.0
tabulate>=0.9.0
Confidence
90% confidence
Finding
The tabulate dependency is also unpinned, creating the same class of supply-chain drift and reproducibility issues as the other entries. While low severity on its own, it contributes to an avoidable insecure dependency-management posture.

Missing User Warnings

Low
Confidence
80% confidence
Finding
This code creates directories and later writes analysis, charts, and report files as part of the pipeline, but the top-level description and CLI help do not clearly warn the user that multiple files will be created on disk. Although progress is printed during execution, there is no upfront disclosure before the write operations begin.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This code creates directories and writes multiple PNG files to the filesystem, but the file header and argument help text do not clearly warn the user that chart images will be saved as output artifacts. Although chart generation implies output, the safety rule asks for visible disclosure of file writes, and the implementation itself has no explicit user-facing notice beyond returning paths afterward.

Static analysis

No suspicious patterns detected.