Back to skill

Security audit

Eastmoney Select Stock 1.0.2

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do stock screening as advertised, but it needs Review because its setup tells users to print an API key and its CSV export writes remote data without spreadsheet-safety handling.

Install only if you are comfortable sending stock-screening queries and your Eastmoney API key to the documented Eastmoney endpoint. Do not follow the `echo $EASTMONEY_APIKEY` instruction; check only whether the variable is set. Treat generated CSV files as untrusted provider data and open them in a viewer that will not evaluate spreadsheet formulas unless the export is sanitized first.

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
SKILL.md:17
Finding
API Key Disclosed Through Terminal Output<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 17–20 **Vulnerability Type**: Credential exposure through insecure diagnostic instructions **Risk Level**: Medium ### Vulnerable Code ```bash echo $EASTMONEY_APIKEY ``` ### Technical Analysis The documented environment-variable check prints the complete `EASTMONEY_APIKEY` value to standard output. Testing whether an environment variable exists does not require disclosing its contents. The secret may consequently be retained in terminal scrollback, CI/CD logs, agent execution transcripts, remote-support recordings, or centralized logging systems. Any party with access to those outputs could recover and reuse the API key. ### Attack Path 1. A user or AI agent follows the documented setup procedure. 2. The shell expands `$EASTMONEY_APIKEY` to its complete secret value. 3. The value is printed to the terminal. 4. Terminal output is retained in scrollback, an agent transcript, a CI log, or another monitoring system. 5. A party with access to that output obtains the key and submits unauthorized requests to the Eastmoney API. ### Impact Assessment Exploitation exposes the privileges associated with the compromised Eastmoney API key. An attacker could consume the victim's API allowance, submit queries under the victim's credentials, and potentially cause service charges, quota exhaustion, or account-level disruption. This issue does not directly grant local operating-system privileges. Its scope is limited to the permissions and resources available through the exposed API credential. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions Replace the secret-revealing command with a presence check that never prints the credential: ```bash if [ -n "${EASTMONEY_APIKEY:-}" ]; then echo "EASTMONEY_APIKEY is set" else echo "EASTMONEY_APIKEY is not set" fi ``` Additional hardening measures should include: - Explicitly instruct users not to print, log, or paste the API key into conversations. - Mask the variable in CI/CD and agent execution platforms. - Redact authentication headers from HTTP debugging and error logs. - Rotate the API key immediately if it has already appeared in retained output. - Use a dedicated secret manager where supported. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/stock_screen.py:86
Finding
Spreadsheet Formula Injection in CSV Export<![CDATA[ ## Vulnerability Details **File Location**: `scripts/stock_screen.py`, lines 86–101 **Vulnerability Type**: CSV/spreadsheet formula injection **Risk Level**: Medium ### Vulnerable Code ```python headers = [column_map[key] for key in data_list[0].keys() if key in column_map] print("\t".join(headers[:5])) print("-" * 100) for row in data_list[:10]: row_data = [str(row[key]) for key in data_list[0].keys() if key in column_map] print("\t".join(row_data[:5])) csv_filename = f"选股结果_{keyword[:20]}.csv".replace("/", "_").replace("\\", "_") with open(csv_filename, "w", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=headers) writer.writeheader() for row in data_list: csv_row = {column_map[key]: value for key, value in row.items() if key in column_map} writer.writerow(csv_row) ``` ### Technical Analysis Column titles and stock-data values received from the remote API are written directly into a CSV file without neutralizing spreadsheet formula prefixes. Values beginning with characters such as `=`, `+`, `-`, or `@` may be interpreted as formulas when the file is opened in Microsoft Excel, LibreOffice Calc, or another spreadsheet application. CSV quoting performed by Python's `csv` module preserves CSV structure but does not prevent spreadsheet applications from evaluating cell contents as formulas. Therefore, a compromised API, manipulated upstream data source, or maliciously crafted returned record could place an executable formula in either a header or data cell. ### Attack Path 1. An attacker compromises or influences data returned by the remote stock-screening service. 2. A returned column title or value begins with a spreadsheet formula prefix, such as `=HYPERLINK(...)` or another application-supported expression. 3. The script copies the value unchanged into the generated CSV file. 4. The user opens the exported file in a spreadsheet application. 5. The application evaluates the cel ...[truncated 1064 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Sanitize every API-controlled header and value before writing it to CSV. Values that begin with formula-control characters, including after leading whitespace, should be forced to text. For example: ```python def sanitize_csv_cell(value): if value is None: return "" text = str(value) if text.lstrip().startswith(("=", "+", "-", "@")): return "'" + text return text safe_headers = [sanitize_csv_cell(header) for header in headers] with open(csv_filename, "w", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=safe_headers) writer.writeheader() for row in data_list: csv_row = { sanitize_csv_cell(column_map[key]): sanitize_csv_cell(value) for key, value in row.items() if key in column_map } writer.writerow(csv_row) ``` The implementation should also: - Apply protection to both headers and data values. - Account for leading spaces, tabs, carriage returns, and other characters that spreadsheet applications may ignore before formula detection. - Prefer an export format that supports explicit text cell types when practical. - Treat all remote API fields as untrusted, even when the service is normally trusted. - Add automated tests covering values beginning with `=`, `+`, `-`, `@`, tabs, and leading whitespace. - Document that existing unsanitized exports should be opened only in a restricted or non-evaluating viewer. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented purpose does not fully match the implemented behavior: the example code performs external API calls using an API key and writes a CSV file locally, while those operational behaviors are not clearly declared as capabilities in the skill contract. This mismatch can mislead reviewers and users about data flow and side effects, which is a security concern because hidden egress and local persistence reduce informed consent and oversight.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill uses sensitive capabilities—environment variable access, outbound network requests, and local file writes—but does not declare any tool scope or permission boundaries. This increases the risk of overbroad execution in hosts that rely on manifest-declared permissions, making it harder to audit what data can leave the system or what local artifacts can be created.

External Transmission

Medium
Category
Data Exfiltration
Content
2. 使用POST请求调用接口:
   ```bash
   curl -X POST --location 'https://mkapi2.dfcfs.com/finskillshub/api/claw/stock-screen' \
   --header 'Content-Type: application/json' \
   --header "apikey: $EASTMONEY_APIKEY" \
   --data '{"keyword": "选股条件", "pageNo": 1, "pageSize": 20}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The script's natural-language interface, usage instructions, errors, and output are presented only in Chinese, which imposes a specific language on users without opt-in or alternative locale support. This matches the policy category for language or locale restrictions because no user-selectable language option or justification is provided in the file.

External Transmission

Medium
Category
Data Exfiltration
Content
}
    
    try:
        response = requests.post(url, headers=headers, json=data)
        response.raise_for_status()
        result = response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
}
    
    try:
        response = requests.post(url, headers=headers, json=data)
        response.raise_for_status()
        result = response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Tainted flow: 'headers' from requests.post (line 81, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
}
    
    try:
        response = requests.post(url, headers=headers, json=data)
        response.raise_for_status()
        result = response.json()
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest describes the skill as supporting stock screening, querying sector constituents, and recommendation-related tasks, which reads as a data retrieval/analysis capability. This script also persists full query results to a local CSV file, adding a file-write/export behavior not reflected in the stated description.

Context-Inappropriate Capability

Low
Confidence
81% confidence
Finding
The manifest focuses on stock selection and related market queries, but the implementation also depends on reading a secret from the process environment. While common operationally, credential access is not part of the described end-user capability and is not justified by the manifest text itself.

Static analysis

No suspicious patterns detected.