Back to skill

Security audit

comparable-company-analysis

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but generated Excel reports can include active formulas from API-controlled data, so users should review it before installing.

Install only if you are comfortable providing an Eastmoney EM_API_KEY and generating local Excel files from that API. Treat the generated workbook as untrusted until formula sanitization is added; inspect or open reports with spreadsheet protections enabled, especially when data comes from a remote service.

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

Warning
Location
scripts/excel_theme.py:190
Finding
API-Controlled Excel Formula Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/excel_theme.py`, lines 190–195 and 264–266 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python cell_value = value # A列=公司名称,B列=股票代码;从C列开始尝试转数字。 if col_idx >= 3: cell_value = _coerce_numeric(value) cell = ws.cell(row=current_row, column=col_idx, value=cell_value) if col_idx >= 3 and isinstance(cell_value, (int, float)): num_fmt = _thousand_number_format_from_raw(value) ``` API-provided title fields are also written directly: ```python ws.cell(row=1, column=1, value=title) ws.cell(row=2, column=1, value=input_title) ws.cell(row=3, column=1, value=frontend_title) ``` ### Technical Analysis The workbook content originates from the remote comparable-company API. API-controlled table values and title fields are passed directly to `openpyxl` cells without neutralizing spreadsheet formula prefixes. `openpyxl` treats strings beginning with `=` as formulas. The first two table columns bypass `_coerce_numeric()` entirely, while later columns preserve values that cannot be converted to numbers. Consequently, an API response containing a value such as `=HYPERLINK(...)` can be stored as an executable spreadsheet formula rather than literal text. Values beginning with `+`, `-`, or `@` may also receive formula-like treatment in some spreadsheet applications and should be considered unsafe. The remote API request itself is consistent with the Skill's declared functionality: `scripts/get_data.py` sends the user-supplied company query and `EM_API_KEY` over HTTPS to the documented Eastmoney endpoint. No unrelated environment variables, local files, or system information were observed being transmitted. The security issue is therefore not the necessary network operation, but the lack of a trust-boundary check when remote response data is converted into an Excel workbook. ### Attack Path 1. An attacker compromises, manipulates, or otherwise control ...[truncated 1643 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Introduce a centralized function that converts all untrusted strings into literal spreadsheet text before writing them to cells: ```python def _safe_excel_value(value: Any) -> Any: if not isinstance(value, str): return value # Preserve the displayed content while preventing formula interpretation. if value.startswith(("=", "+", "-", "@")): return "'" + value return value ``` 2. Apply this function to every API-derived string, including table cells and title fields: ```python cell_value = value if col_idx >= 3: cell_value = _coerce_numeric(value) cell_value = _safe_excel_value(cell_value) cell = ws.cell(row=current_row, column=col_idx, value=cell_value) ``` ```python ws.cell(row=1, column=1, value=_safe_excel_value(title)) ws.cell(row=2, column=1, value=_safe_excel_value(input_title)) ws.cell(row=3, column=1, value=_safe_excel_value(frontend_title)) ``` 3. Where values are semantically identifiers, such as company names and stock codes, explicitly set the cells to text and do not permit formula interpretation. 4. Validate the API response against a strict schema. Enforce expected types, maximum lengths, and permitted formats for titles, company names, stock codes, and numeric metrics. 5. Add regression tests using values beginning with `=`, `+`, `-`, and `@`. Reopen generated workbooks with `openpyxl` and confirm that the resulting cells contain literal text rather than formulas. 6. Continue using HTTPS for the declared API request, and restrict authentication headers to the documented Eastmoney endpoint. Avoid following redirects to untrusted hosts with the API key attached. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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 (6)

Tainted flow: 'req' from os.environ.get (line 101, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
)

    try:
        with urllib_request.urlopen(req, timeout=TIMEOUT_SECONDS) as resp:
            raw_body = resp.read().decode("utf-8", errors="replace")
    except urllib_error.HTTPError as exc:
        err_body = exc.read().decode("utf-8", errors="replace") if exc.fp else ""
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill requires environment-variable access and makes outbound API calls, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates an over-privilege and governance gap: an agent runtime may permit broader tool or network use than intended, making review, sandboxing, and policy enforcement harder.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The skill description is written as a Chinese-only capability statement and the file provides no indication that users may choose another language or locale for interaction. Under the policy rule, a language constraint should either be optional or explicitly documented as a justified region-specific limitation.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The module docstring states raw API payloads are not persisted locally, but the code stores the full response in result['raw'] and the CLI prints the entire result as formatted JSON. While this is not file persistence, it can still expose sensitive or proprietary upstream data to stdout, calling processes, logs, or orchestrator telemetry, creating an information disclosure risk and a misleading trust boundary for users of the skill.

Missing User Warnings

Low
Confidence
82% confidence
Finding
This code creates an output directory and saves an Excel workbook, which is a file write operation. In the saving function itself there is no confirmation prompt, logging statement, or comment/docstring warning that the function will create directories and write a file; the later CLI printout is outside this operation and does not document the side effect for other callers.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The manifest describes a comparable-company analysis tool that calls an analysis API and generates reports, but it does not mention accessing local environment configuration or credentials. This file requires and reads EM_API_KEY from the environment, which is a broader capability than the business-level purpose alone suggests.

Static analysis

No suspicious patterns detected.