Back to skill

Security audit

Document Generator (Word & Excel)

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Word and Excel file generator, with manageable cautions around untrusted spreadsheet data and unpinned Python dependencies.

Install in a virtual environment and consider pinning dependencies. Only use trusted JSON data for spreadsheets, especially before sending workbooks to clients, because cell text beginning with formula characters may behave as an active spreadsheet formula. Treat generated SMSF, accounting, and compliance documents as drafts requiring professional review, as the skill itself states.

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
create_xlsx.py:115
Finding
Untrusted JSON Values Can Be Embedded as Active Spreadsheet Formulas<![CDATA[ ## Vulnerability Details **File Location**: `create_xlsx.py`, lines 115–127 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python def populate_sheet_from_data(worksheet, sheet_data: dict[str, Any]) -> None: headers = sheet_data.get("headers", []) rows = sheet_data.get("rows", []) title = sheet_data.get("title") if title: worksheet.title = str(title)[:31] if headers: for col, header in enumerate(headers, start=1): worksheet.cell(row=1, column=col, value=header) style_header_row(worksheet, 1, len(headers)) start_row = 2 if headers else 1 for row_index, row_values in enumerate(rows, start=start_row): for col_index, value in enumerate(row_values, start=1): worksheet.cell(row=row_index, column=col_index, value=value) autosize_columns(worksheet) ``` ### Technical Analysis Values obtained from the input JSON are passed directly to `openpyxl` cells without distinguishing ordinary text from spreadsheet formulas. In particular, a string beginning with `=` is stored by `openpyxl` as a formula rather than as literal text. An attacker who can influence the JSON input can therefore insert formulas such as `=HYPERLINK(...)`, external workbook references, or deceptive expressions. The resulting workbook appears to be an ordinary generated document, but attacker-controlled formulas may be evaluated when a recipient opens or refreshes it. This is a data-to-code interpretation flaw in the spreadsheet output layer. No shell or Python code execution occurs in the generator itself, but untrusted input becomes active content in the recipient's spreadsheet application. ### Attack Path 1. An attacker supplies or influences a JSON data file accepted through the `--data` option. 2. The attacker places a formula string in a row value, for example: ```json { "headers": ["Description", "Link"], "rows": [ ["Revi ...[truncated 1288 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Treat JSON-derived strings as literal text by default and allow formulas only through an explicit, separately validated schema. 1. Sanitize imported strings before assigning them to cells: ```python def safe_cell_value(value: Any) -> Any: if isinstance(value, str) and value.startswith(("=", "+", "-", "@")): return "'" + value return value ``` 2. Apply the conversion to both headers and row values: ```python worksheet.cell( row=row_index, column=col_index, value=safe_cell_value(value), ) ``` 3. If formulas are a required feature, represent them with an explicit structure such as: ```json {"type": "formula", "value": "=SUM(B2:B10)"} ``` Formula support should be disabled by default and enabled only for trusted input. Validate permitted functions and prohibit external references, hyperlinks, dynamic data exchange syntax, and unexpected workbook references. 4. Validate that `headers` and `rows` are arrays and that each row is an array before processing them. 5. Add regression tests confirming that values such as `=1+1`, `=HYPERLINK(...)`, `+CMD`, `-1+2`, and `@SUM(...)` are stored and displayed as literal text unless formula processing has been explicitly authorized. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Dependencies Are Installed Without Exact Version or Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt`, lines 1–2 **Additional References**: `README.md`, line 27; `SKILL.md`, line 209 **Vulnerability Type**: Uncontrolled third-party dependency resolution **Risk Level**: Low ### Vulnerable Code ```text python-docx>=1.1.0 openpyxl>=3.1.0 ``` The documented installation process resolves these open-ended constraints: ```bash pip install -r requirements.txt ``` ### Technical Analysis The requirements file specifies only minimum versions. Consequently, an installation can resolve to any later package version available from the configured Python package index. No lock file or package hashes are provided to ensure that installations use artifacts reviewed during the audit. This creates non-reproducible builds and expands supply-chain exposure. A future compromised, malicious, or incompatible release satisfying either minimum constraint could be installed automatically. Python packages can execute code during installation or whenever their modules are imported by the scripts. The identified packages are legitimate package names; the project does not demonstrate typosquatting or use of an untrusted package source. The issue is the absence of exact version and artifact-integrity controls, rather than evidence that the current dependencies are malicious. ### Attack Path 1. A user follows the documented command `pip install -r requirements.txt`. 2. `pip` queries the configured package index and selects a release satisfying `>=1.1.0` or `>=3.1.0`. 3. Because no exact version or hash is required, a newer release can be selected without project review. 4. If that release or its distribution infrastructure has been compromised, malicious package code may run during installation or import. 5. The code executes with the permissions of the user or automation account performing installation or running the document generator. This path depends on a compromised dependency release, package index, or d ...[truncated 802 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin dependencies to exact versions that have been reviewed and tested: ```text python-docx==<reviewed-version> openpyxl==<reviewed-version> ``` 2. Generate a lock file containing transitive dependencies rather than controlling only the two direct dependencies. 3. Require cryptographic hashes for downloaded distributions. For pip-based workflows, generate a hash-pinned requirements file and install it with: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 4. Prefer a trusted internal package mirror or an explicitly configured approved package index in regulated or production environments. 5. Add automated dependency vulnerability and release monitoring. Upgrade dependencies through a reviewed change process rather than resolving arbitrary future versions during installation. 6. Build and test in an isolated virtual environment or container under a non-privileged account. Avoid installing project dependencies as root or into a system-wide Python environment. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code’s primary purpose is creating .docx files, which partially matches the declared description. However, the description materially overstates the capability by claiming Excel workbook generation as well. There is no spreadsheet library usage, no .xlsx output handling, and the output path is explicitly required to end with .docx. Because the declared purpose includes both Word and Excel file generation and workbook-related triggers, while the actual code supports only Word documents, this is a meaningful description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The description claims the skill generates both Word and Excel files as downloadable outputs. However, the provided code chunk is exclusively an Excel workbook generator using openpyxl. It validates an .xlsx output path, supports budget and invoice spreadsheet templates, loads JSON data into sheets, applies spreadsheet styling, and saves a workbook. There is no code for creating .docx files, no Word library usage, and no report/document generation outside Excel. This is a material description-to-behavior mismatch because one of the core declared capabilities—Word document generation—is absent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The manifest description lists triggers such as "create a Word doc," "make an Excel spreadsheet," and especially "generate a report," which are broad enough to overlap with common user requests that may not actually require this skill. Although there is a negative condition on L008, the trigger list still lacks tighter constraints distinguishing file-generation requests from general drafting or reporting requests.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Safety rules

1. **Only write files to locations the user has explicitly approved.** Do not write to shared, client, or regulated folders without confirmation.
2. **Do not overwrite existing files** unless the user has clearly asked for that (use `--force` only when authorised).
3. **All output is a draft.** Never present generated documents as final, signed, or legally compliant without separate professional review.
4. **SMSF and compliance documents must be reviewed** by a qualified accountant, auditor, or adviser before use with a client or regulator.
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
3. **All output is a draft.** Never present generated documents as final, signed, or legally compliant without separate professional review.
4. **SMSF and compliance documents must be reviewed** by a qualified accountant, auditor, or adviser before use with a client or regulator.
5. **Do not interpolate free-form user input directly into shell commands.** Use structured JSON input instead.
6. **Do not execute arbitrary code** supplied by the user as part of document content or config.

---
Confidence
80% confidence
Finding
Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Vague Triggers

Low
Confidence
85% confidence
Finding
The section says to trigger the skill when the user asks for a file, but one listed example—"Make a checklist I can send to the client"—does not itself clearly specify a Word or Excel file. That weakens the otherwise narrow scope and could cause invocation on general content-generation requests.

Unpinned Dependencies

Low
Category
Supply Chain
Content
python-docx>=1.1.0
openpyxl>=3.1.0
Confidence
96% confidence
Finding
The dependency is specified with a lower bound only, so builds can resolve to different versions over time and may unexpectedly pull a vulnerable or incompatible release. In a file-generation skill that handles DOCX output, this increases supply-chain uncertainty and makes it difficult to verify whether a safe version of python-docx is consistently installed.

Unverifiable Dependency: python-docx has 2 known advisory(ies) (CVE-2016-5851 (Improper Restriction of XML External Entity Reference in python-docx); CVE-2016-5851 (python-docx before 0.8.6 allows context-dependent attackers to conduct XML Exter)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding
python-docx has historical XXE-related advisories, and because the manifest does not pin a version, there is no reliable assurance that deployment will avoid affected releases. In a document-creation skill this is somewhat contextualized by expected output generation rather than parsing untrusted DOCX, but the unresolved version still leaves a plausible path to deploying a known-vulnerable package.

Unpinned Dependencies

Low
Category
Supply Chain
Content
python-docx>=1.1.0
openpyxl>=3.1.0
Confidence
96% confidence
Finding
The open-ended version specifier allows environment-dependent installation results, which weakens reproducibility and can introduce vulnerable package versions without code changes. Because this skill creates Excel workbooks, using an unpinned parser/writer library adds avoidable supply-chain risk to document-processing functionality.

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
87% confidence
Finding
openpyxl has historical XXE-related advisories, and the unpinned requirement makes it impossible to confirm that affected versions will not be installed. The skill’s stated purpose is workbook generation rather than ingesting attacker-controlled XLSX content, which reduces immediate exploitability, but the dependency state still represents a real, preventable supply-chain exposure.

Static analysis

No suspicious patterns detected.