Back to skill

Security audit

"i问财选股技能"

Security checks for vulnerabilities and agentic risk

Overview

This stock-screening skill appears purpose-aligned, but it needs review because it can auto-activate broadly, fetch/read user-supplied content, and write Excel files with weak output and spreadsheet-safety controls.

Install only if you are comfortable with the agent using web access and local files for stock screening. Ask it to confirm before reading files or writing Excel output, use a controlled export directory, and treat generated spreadsheets and stock picks as unverified analysis rather than investment advice.

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/generate_stock_excel.py:33
Finding
Spreadsheet Formula Injection in Generated Excel Workbooks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_stock_excel.py`, lines 33–37 **Vulnerability Type**: Spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python with pd.ExcelWriter(output_file, engine='openpyxl') as writer: for sheet in sheets_data: df = pd.DataFrame(sheet['rows'], columns=sheet['headers']) # Excel sheet name max 31 chars sheet_name = sheet['name'][:31] df.to_excel(writer, sheet_name=sheet_name, index=False) ``` ### Technical Analysis The script places headers and row values directly into a Pandas DataFrame and exports them to an Excel workbook without neutralizing formula-like strings. The intended workflow populates these fields with externally retrieved stock-query data, while direct command-line invocation also permits a caller to supply arbitrary cell values. In particular, a string beginning with `=` can be stored as an Excel formula by the `openpyxl` export engine rather than as literal text. Other spreadsheet formats or applications may also interpret values beginning with `+`, `-`, or `@` as formulas. An attacker who controls a returned field or invocation argument could inject a formula such as an external reference, deceptive hyperlink, or another supported spreadsheet expression. Formula behavior depends on the spreadsheet application and its security settings; some external operations may require user confirmation or may be disabled by default. ### Attack Path 1. An attacker controls stock-query content, another data source used by the Skill, or arguments passed directly to the script. 2. The attacker places a formula-prefixed string in a header or row value. 3. The value is inserted into `sheet['headers']` or `sheet['rows']`. 4. `df.to_excel()` writes the value without converting it to safe literal text. 5. A user opens the generated workbook in a spreadsheet application. 6. The application evaluates the formula or displays an interaction pr ...[truncated 825 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Sanitize all externally sourced headers and cell values before creating the DataFrame: 1. Treat strings whose first non-whitespace character is `=`, `+`, `-`, or `@` as potentially unsafe. 2. Prefix unsafe values with a single quote or otherwise force the destination cell type to literal text. 3. Apply sanitization recursively to every header and row value, not only selected display columns. 4. If CSV export is implemented, apply the same protection because CSV files are also susceptible to spreadsheet formula injection. 5. Add tests covering leading whitespace, tabs, newlines, and each formula marker. Example hardening logic: ```python def safe_spreadsheet_value(value): if isinstance(value, str) and value.lstrip().startswith(('=', '+', '-', '@')): return "'" + value return value safe_headers = [safe_spreadsheet_value(v) for v in sheet['headers']] safe_rows = [ [safe_spreadsheet_value(v) for v in row] for row in sheet['rows'] ] df = pd.DataFrame(safe_rows, columns=safe_headers) ``` Where possible, explicitly configure exported cells as text and validate the resulting workbook to ensure formula cells are not created from untrusted data. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/generate_stock_excel.py:33
Finding
Unrestricted Output Path Allows Overwriting Writable Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_stock_excel.py`, lines 33 and 64 **Vulnerability Type**: Unrestricted file write and overwrite **Risk Level**: Low ### Vulnerable Code The output path is consumed directly by the Excel writer: ```python with pd.ExcelWriter(output_file, engine='openpyxl') as writer: ``` The path originates directly from the first command-line argument: ```python output_file = sys.argv[1] ``` No canonicalization, directory confinement, symlink protection, extension validation, or overwrite check is performed between these operations. ### Technical Analysis Although the documented workflow specifies a workspace destination, direct script invocation accepts an arbitrary filesystem path. `pd.ExcelWriter` then creates or replaces that path using the permissions of the Agent process. A caller capable of influencing the command-line argument can therefore target any existing file writable by the process. Relative traversal paths, absolute paths, and paths involving symbolic links are not rejected. The generated workbook contents may consequently replace an unrelated writable file. This finding does not itself bypass operating-system access controls. Its reach is restricted to locations for which the executing process already has write permission. ### Attack Path 1. An attacker influences the first command-line argument supplied to `generate_stock_excel.py`. 2. The attacker supplies an absolute path, traversal path, or symlink-resolved path identifying a writable target. 3. The value is assigned directly to `output_file`. 4. `pd.ExcelWriter` opens the target for workbook output. 5. The existing target is replaced or corrupted with Excel workbook data. ### Impact Assessment An attacker may overwrite or corrupt files writable by the Agent process, including workspace documents and application data. If the process has unusually broad privileges, the affected scope increases accordingly. The code does not ...[truncated 192 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Constrain all output to a dedicated export directory and reject paths that escape it: 1. Define an approved output directory owned by the application. 2. Accept only a filename rather than an arbitrary path. 3. Resolve both the approved directory and candidate path with `pathlib.Path.resolve()`. 4. verify with `Path.is_relative_to()` that the resolved candidate remains beneath the approved directory. 5. Reject symlinks and non-`.xlsx` extensions. 6. Generate unpredictable filenames server-side instead of accepting complete paths from callers. 7. Refuse to overwrite existing files unless replacement was explicitly authorized. 8. Run the Skill with minimal filesystem permissions. Example confinement logic: ```python from pathlib import Path export_dir = Path("/Users/tututu/.openclaw/workspace").resolve() requested_name = Path(sys.argv[1]).name if not requested_name.lower().endswith(".xlsx"): raise ValueError("The output file must use the .xlsx extension") output_path = (export_dir / requested_name).resolve() if not output_path.is_relative_to(export_dir): raise ValueError("Output path escapes the approved export directory") if output_path.exists(): raise FileExistsError("Refusing to overwrite an existing file") output_file = str(output_path) ``` For stronger overwrite and race-condition protection, create the destination using an exclusive-create operation or write to a securely created temporary file inside the approved directory and atomically rename it only after validating that the destination does not exist. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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 (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill claims it will analyze user-provided links/files/text, identify relevant sectors, query i问财, and return screened stock results, but the finding indicates the implementation does not actually perform those actions and mainly exports data. This kind of description-behavior mismatch is dangerous because users and downstream agents may rely on outputs as if they were based on real market analysis and external queries, creating integrity and decision-risk from fabricated or incomplete results.

Vague Triggers

High
Confidence
95% confidence
Finding
The trigger condition '模型自行根据语义判断需要选股的场景' allows open-ended self-activation without a precise boundary, which can cause the skill to run on loosely related prompts or sensitive financial discussion that did not explicitly request stock screening. In a finance-oriented skill, overbroad invocation increases the chance of unintended external access, misleading investment-style output, or unwanted file generation based on misunderstood user intent.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The auto-activation triggers are broad and loosely scoped, including generic phrases like 'XX选股', '分析利好哪些行业', and any link/text followed by a request to analyze and pick stocks. In an agent environment, this can cause the skill to activate on ambiguous user input or unrelated content, leading to unintended web access, content processing, and stock-screening actions without sufficiently clear user intent.

Vague Triggers

Medium
Confidence
88% confidence
Finding
Several triggers such as 'XX选股', '根据XX选股', and '分析利好哪些行业' are broad enough to match many contexts without reliably distinguishing whether the user wants financial screening, general explanation, or something else. This can cause accidental invocation and output of authoritative-seeming stock recommendations in situations where the user did not clearly consent to that workflow.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill specifies generating and saving an Excel file to a local filesystem path without stating that the user will be warned or asked for consent first. Unannounced file writes can surprise users, create privacy or storage issues, and in multi-skill environments may leave behind sensitive financial data artifacts on disk.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The script has an undocumented demo mode that activates when no arguments are provided and writes a file to a hard-coded absolute path under a local workspace directory. In an agent/tooling context, unexpected file writes can violate least surprise, leak artifacts into sensitive locations, or fail unpredictably depending on the runtime environment; while not directly code execution, it is unsafe behavior for automation.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
The module docstring is entirely in Chinese and the usage/help text does not indicate any language choice, which can impose a specific language on users. In addition, the built-in demo output filename later uses Chinese characters, reinforcing a fixed locale without opt-in or a stated region-specific purpose.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The default demo filename includes the Chinese phrase "选股结果", which enforces a specific language/locale in generated artifacts. The file does not offer an alternative naming locale or explain that the skill is intentionally limited to a Chinese-language context.

Static analysis

No suspicious patterns detected.