Back to skill

Security audit

Mx Stock Simulator

Security checks for vulnerabilities and agentic risk

Overview

This stock simulator is not clearly malicious, but it deserves Review because it uses an API key for account-like trading APIs and stores financial responses locally without strong scoping, confirmation, or retention controls.

Install only if you trust the Eastmoney/Miaoxiang API key and endpoint configuration. Keep MX_API_URL at the documented trusted HTTPS host, use a low-privilege revocable API key, explicitly confirm any buy/sell/cancel request before allowing an agent to run it, and periodically delete or protect the raw JSON files written under /root/.openclaw/workspace/mx_data/output.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mx_stock_simulator.py:11
Finding

API Credential Can Be Disclosed to an Untrusted Configurable Endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/mx_stock_simulator.py, lines 11-25
Vulnerability Type: Unrestricted credential-bearing outbound request
Risk Level: High

Vulnerable Code

python
MX_APIKEY = os.environ.get('MX_APIKEY')
MX_API_URL = os.environ.get('MX_API_URL', 'https://mkapi2.dfcfs.com/finskillshub')
OUTPUT_DIR = '/root/.openclaw/workspace/mx_data/output'

os.makedirs(OUTPUT_DIR, exist_ok=True)

def make_request(endpoint: str, body: Dict[str, Any], output_prefix: str) -> None:
    """发送POST请求并保存结果"""
    full_url = f"{MX_API_URL}{endpoint}"
    headers = {
        'apikey': MX_APIKEY,
        'Content-Type': 'application/json'
    }
    
    try:
        response = requests.post(full_url, headers=headers, json=body)

Technical Analysis

The application reads MX_API_URL directly from the environment and sends the secret MX_APIKEY to the resulting URL. It does not parse or validate the URL, enforce HTTPS, restrict the destination hostname or port, reject embedded credentials, or explicitly disable redirects.

Environment variables are configuration inputs rather than inherently trusted values. If an attacker, deployment configuration, wrapper process, or compromised environment can modify MX_API_URL, the credential-bearing request can be redirected to an attacker-controlled HTTP or HTTPS server. Plain HTTP values would additionally expose the credential to network interception.

Because the API key is placed in a custom apikey header, redirect behavior also needs explicit control. The implementation does not verify the destination of any redirect before a subsequent request is made.

Attack Path

  1. An attacker gains the ability to influence the process environment or deployment configuration.
  2. The attacker sets MX_API_URL to an endpoint under their control, such as https://attacker.example.
  3. A user invokes any implemented query for positions, fu ...[truncated 1027 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse the base URL with urllib.parse.urlparse.
  2. Require the https scheme and reject plaintext HTTP.
  3. Allowlist the documented hostname, mkapi2.dfcfs.com, unless additional trusted hosts are explicitly required.
  4. Reject embedded usernames, passwords, fragments, unexpected ports, malformed paths, and ambiguous hostnames.
  5. Disable automatic redirects with allow_redirects=False, or validate every redirect destination before resending credentials.
  6. Construct URLs using a safe URL-joining mechanism rather than direct string concatenation.
  7. Fail closed when the API key is missing or the endpoint fails validation.
  8. Use a narrowly scoped, revocable API credential and rotate any credential potentially exposed through an untrusted configuration.

Example validation policy:

python
from urllib.parse import urlparse

ALLOWED_API_HOSTS = {"mkapi2.dfcfs.com"}

parsed = urlparse(MX_API_URL)
if (
    parsed.scheme != "https"
    or parsed.hostname not in ALLOWED_API_HOSTS
    or parsed.username is not None
    or parsed.password is not None
    or parsed.port not in (None, 443)
):
    raise ValueError("Untrusted API URL")

response = requests.post(
    full_url,
    headers=headers,
    json=body,
    allow_redirects=False,
    timeout=(5, 30),
)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mx_stock_simulator.py:13
Finding

Sensitive Account Responses Are Persisted Without Restrictive File Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/mx_stock_simulator.py, lines 13-31
Vulnerability Type: Insecure storage of sensitive financial and account data
Risk Level: Medium

Vulnerable Code

python
OUTPUT_DIR = '/root/.openclaw/workspace/mx_data/output'

os.makedirs(OUTPUT_DIR, exist_ok=True)

def make_request(endpoint: str, body: Dict[str, Any], output_prefix: str) -> None:
    """发送POST请求并保存结果"""
    full_url = f"{MX_API_URL}{endpoint}"
    headers = {
        'apikey': MX_APIKEY,
        'Content-Type': 'application/json'
    }
    
    try:
        response = requests.post(full_url, headers=headers, json=body)
        response.raise_for_status()
        result = response.json()
        
        output_path = os.path.join(OUTPUT_DIR, f"{output_prefix}_raw.json")
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(result, f, ensure_ascii=False, indent=2)

Technical Analysis

Raw API responses containing holdings, balances, asset values, and order history are written to persistent storage. The application does not explicitly establish restrictive permissions for either the output directory or generated files.

os.makedirs() and open(..., 'w') derive effective permissions from process defaults and the active umask. Consequently, confidentiality depends on external runtime configuration rather than an application-enforced policy. Existing files are also opened with truncation rather than securely created with exclusive access.

The records have no expiration, cleanup, or retention controls. Sensitive account data can therefore remain available after the request has completed.

The filename also incorporates command-line query text. Although spaces are replaced, other path-significant characters are not sanitized. This broadens the unsafe file-handling surface and should be addressed with a fixed identifier or strict filename allowlist.

...[truncated 1172 chars]

Remediation
View remediation

Remediation Suggestions

  1. Avoid writing raw responses unless persistence is explicitly requested.
  2. Create the output directory with mode 0700 and verify permissions if it already exists.
  3. Create output files atomically with mode 0600, preferably using os.open() with O_CREAT | O_EXCL | O_WRONLY.
  4. Use generated identifiers rather than unsanitized user query text in filenames.
  5. Reject path separators, traversal tokens, control characters, and unsupported filename characters if user-derived names remain necessary.
  6. Apply a documented retention period and securely delete expired records.
  7. Minimize stored content by removing unnecessary account identifiers and financial fields.
  8. Do not place sensitive output in a shared workspace unless access controls are verified.

Example hardening:

python
import os
import secrets

os.makedirs(OUTPUT_DIR, mode=0o700, exist_ok=True)
os.chmod(OUTPUT_DIR, 0o700)

output_path = os.path.join(
    OUTPUT_DIR,
    f"mx_stock_simulator_{secrets.token_hex(8)}_raw.json",
)
fd = os.open(output_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, "w", encoding="utf-8") as f:
    json.dump(result, f, ensure_ascii=False, indent=2)

T08 · Insecure Dependencies

Note
Location
scripts/requirements.txt:1
Finding

Third-Party Dependency Is Unpinned and Lacks Integrity Verification

Content
View full analysis

Vulnerability Details

File Location: scripts/requirements.txt, line 1
Vulnerability Type: Unpinned dependency and non-reproducible supply chain
Risk Level: Low

Vulnerable Code

text
requests

Technical Analysis

The project declares requests without a version constraint or package hash. Dependency installation can therefore resolve to different releases at different times. The package name itself is legitimate, and the audit found no evidence that the currently resolved package is malicious; the issue is the absence of version and integrity controls.

If a future release is compromised, removed, becomes incompatible, or introduces a security regression, a fresh installation may automatically consume it. The declaration also prevents reliable reproduction of the exact dependency set reviewed during this audit because transitive dependencies are not locked.

Attack Path

  1. A deployment or user performs a fresh dependency installation.
  2. The package resolver selects the latest release satisfying the unrestricted declaration.
  3. If that release or one of its resolved transitive dependencies has been compromised or contains a security regression, the affected package is installed.
  4. Package installation hooks or imported runtime code execute with the permissions of the installation or skill process.
  5. The malicious or vulnerable dependency can access data and resources available to that process, potentially including environment variables and outbound network access.

This is a conditional supply-chain path. No compromise of the legitimate requests package was identified in the reviewed project.

Impact Assessment

A compromised dependency would execute with the same privileges as the Python process. In this project, that process can access MX_APIKEY, make network requests, and write into the configured output directory. If dependency installation is performed with elevated permi ...[truncated 272 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin requests to a specifically reviewed version.
  2. Lock all transitive dependencies rather than only the direct dependency.
  3. Generate and require cryptographic hashes, for example with pip-tools and pip install --require-hashes.
  4. Install only from an approved HTTPS package index.
  5. Run dependency vulnerability and license scanning in continuous integration.
  6. Use an automated, reviewed update process so pinned dependencies continue to receive security patches.
  7. Install dependencies in an isolated virtual environment under a non-privileged account.

A lock entry should use an audited current version and its verified distribution hashes rather than an unrestricted package name.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (18)

Tainted flow: 'full_url' from os.environ.get (line 19, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The request target is derived from the MX_API_URL environment variable and used directly in requests.post along with the API key header. If an attacker can influence the environment or deployment configuration, they can redirect authenticated requests to an attacker-controlled host and capture the API key and returned account data; in a trading/account context this makes the issue materially dangerous.

Content

Scanner excerpt · scripts/mx_stock_simulator.py (reported line 26)May include surrounding context.

python
}
    
    try:
        response = requests.post(full_url, headers=headers, json=body)
        response.raise_for_status()
        result = response.json()

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documentation claims a fuller trading capability set than is apparently implemented, which can mislead users and reviewers about the skill's actual behavior and trust model. Security-relevant mismatches are dangerous because users may consent to one set of actions while the implementation performs different ones, including local persistence or partial account access not clearly disclosed.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents capabilities that require network access, environment-variable access, and local file writes, but it does not declare any explicit tool scope or permission boundaries. In a trading-related skill, this creates an unsafe over-privileged design where the agent could access secrets, transmit them to a remote endpoint, and persist sensitive account data locally without transparent guardrails.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill includes state-changing operations such as buy, sell, and cancel, but does not clearly require an explicit confirmation step before executing impactful actions. Even in a simulator, unauthorized or accidental trading operations can alter portfolio state, invalidate tests, and normalize unsafe patterns for real-trading-adjacent workflows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill states that extracted text results and raw JSON API responses will be written to a local output directory, but it does not clearly warn that these files may contain account balances, holdings, order history, and other sensitive trading data. Silent persistence increases the risk of local data exposure, unintended retention, and later exfiltration by other tools or skills.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

This endpoint transmits authenticated account-related data to an external service using an API key from the environment. External transmission is expected for the skill's purpose, but without domain restrictions, secret-handling guarantees, and permission scoping, it creates a real risk of credential misuse or disclosure of portfolio information.

Content

Scanner excerpt · SKILL.md (reported line 130)May include surrounding context.

  • 成功响应:{ }
bash
curl -X POST "${MX_API_URL}/api/claw/mockTrading/positions" \
  -H "apikey: ${MX_APIKEY}" \
  -H "Content-Type: application/json" \
  -d '{

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This external request can place buy or sell orders while carrying an API key in the header, making it a state-changing authenticated transmission. In the context of a trading simulator, the danger is heightened because accidental or unauthorized order submission can directly alter account state and, if the configured base URL is changed, could send trading credentials and order details to an attacker-controlled endpoint.

Content

Scanner excerpt · SKILL.md (reported line 212)May include surrounding context.

  • 委托价格说明:当 useMarketPrice=false 时,price参数必填,且需符合市场规则:沪市价格小数位不超过2位,深市价格小数位不超过3位;当 useMarketPrice=true 时,price参数会被忽略,系统会自动以行情最新价进行买入。
bash
curl -X POST "${MX_API_URL}/api/claw/mockTrading/trade" \
  -H "apikey: ${MX_APIKEY}" \
  -H "Content-Type: application/json" \
  -d '{

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This section documents the cancel API, but the parameter table states type: order=买入, all=一键撤单. That directly conflicts with the surrounding text, which says the operation is for cancelling a specific order or all pending orders; order should refer to single-order cancellation, not buying.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

This authenticated external transmission can cancel one or many orders, which is a sensitive state-changing action. Because the base URL is environment-configurable and there is no documented confirmation or destination restriction, an attacker who influences configuration or prompts could trigger destructive account changes or route sensitive order metadata to an untrusted server.

Content

Scanner excerpt · SKILL.md (reported line 253)May include surrounding context.

  • 股票代码格式说明:仅支持A股,格式为6位数字,例如 600519、000001,系统会自动识别并补全市场号;另外股票代码在type为order时必传。
bash
curl -X POST "${MX_API_URL}/api/claw/mockTrading/cancel" \
  -H "apikey: ${MX_APIKEY}" \
  -H "Content-Type: application/json" \
  -d '{

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

This request sends authenticated order-history data to an external endpoint, exposing potentially sensitive account activity and transaction metadata. While this is aligned with the skill's purpose, the lack of explicit network scoping and local-file warnings makes the data-flow risk real, especially if combined with saved raw JSON outputs.

Content

Scanner excerpt · SKILL.md (reported line 323)May include surrounding context.

| fltOrderStatus | 否 | 0=全部(默认),2=已报,4=已成 等 |

bash
curl -X POST "${MX_API_URL}/api/claw/mockTrading/orders" \
  -H "apikey: ${MX_APIKEY}" \
  -H "Content-Type: application/json" \
  -d '{

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

This endpoint transmits authenticated balance and asset information to an external service, which is sensitive financial data even in a simulated environment. The risk is increased by the combination of environment-sourced credentials, configurable remote endpoint, and documented local storage of raw API responses.

Content

Scanner excerpt · SKILL.md (reported line 414)May include surrounding context.

  • 成功响应:{ }
bash
curl -X POST "${MX_API_URL}/api/claw/mockTrading/balance" \
  -H "apikey: ${MX_APIKEY}" \
  -H "Content-Type: application/json" \
  -d '{

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

All user-facing text, examples, and intent matching are exclusively in Chinese, and the query routing only recognizes Chinese trigger terms. This creates a language/locale constraint without opt-in or explanation, which matches the policy concern for forcing a specific language.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code reads an API key from the environment and sends requests to a remote endpoint for positions, balances, and orders, which likely involve sensitive financial account data. Although it prints success or failure afterward, there is no prior user-facing warning, confirmation, or explanatory comment/docstring disclosing that account-related data will be transmitted over the network using credentials.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/mx_stock_simulator.py (reported line 26)May include surrounding context.

python
}
    
    try:
        response = requests.post(full_url, headers=headers, json=body)
        response.raise_for_status()
        result = response.json()

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest describes a full stock simulation trading system supporting持仓查询、买卖操作、撤单、委托查询、历史成交查询和资金查询. However, the implemented intent routing only calls three query endpoints: positions, balance, and orders. No code exists for buy, sell, cancel-order, or trade-history operations, so the actual behavior is materially narrower than the stated skill description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest/documentation says the skill is not for non-A股 simulation and the stock code input is described as A股-only. However, later sections document returned/handled market identifiers including 港交所 (116) and 纳斯达克 (105), which broadens the represented scope beyond the stated A股-only positioning.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency is specified as just requests with no version pin or constraint, which makes builds non-reproducible and can silently introduce vulnerable or incompatible releases over time. In a stock trading simulator context, dependency drift is more concerning because network-facing code may handle authentication, account data, or transaction-like actions.

Content

Scanner excerpt · scripts/requirements.txt (reported line 1)May include surrounding context.

text
requests

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

Because requests is unpinned, there is no way to verify that the installed version is free from known advisories; the environment could resolve to a release affected by credential leakage, TLS-related, redirect, or other security issues. This is more dangerous in this skill because it interfaces with authenticated APIs for simulated trading, where mishandling sessions, credentials, or responses could expose sensitive financial or account-related data.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.