Back to skill

Security audit

东方财富妙想skills套件/eastmoney MX skills suite

Security checks for vulnerabilities and agentic risk

Overview

This financial skill is mostly coherent, but it can change account/watchlist state, save sensitive results locally, and one script can send the API key to an environment-configured endpoint.

Review this skill before installing. Use a scoped MX_APIKEY, do not set MX_API_URL unless you fully trust the destination, avoid sending confidential portfolio or personal data in free-form queries, and require manual confirmation before using watchlist changes, buy/sell orders, or cancel-all actions. Also be aware that results are saved locally under /root/.openclaw/workspace/mx_data/output unless you change script behavior or clean up the files.

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

Error
Location
scripts/mx_stock_simulator.py:15
Finding

Configurable API endpoint permits API key exfiltration

Content
View full analysis

Vulnerability Details

File Location: scripts/mx_stock_simulator.py, lines 15–16 and 50–61
Vulnerability Type: Unrestricted credential-bearing network destination
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')
python
def make_request(endpoint, payload):
    """Send a POST request to the API."""
    url = f"{MX_API_URL}{endpoint}"
    headers = {
        'apikey': MX_APIKEY,
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"Request failed: {str(e)}")
        return None

Technical Analysis

The simulated-trading client allows the request origin to be overridden through the MX_API_URL environment variable. It does not validate the URL scheme, hostname, port, or effective destination before attaching the MX_APIKEY credential.

Consequently, a process or configuration source capable of influencing the script's environment can redirect every simulator request to an arbitrary server. The script will transmit the API key in the apikey header along with operation payloads. The code also relies on the default redirect behavior of requests, without independently verifying the final response origin.

This behavior exceeds the documented network privilege. README.md and SKILL.md state that data is sent only to the Eastmoney API domain, but the implementation permits any destination supplied through the environment.

Attack Path

  1. An attacker influences a deployment manifest, shell profile, wrapper script, process environment, or copied setup command used to launch the Skill.
  2. The attacker sets MX_API_URL to an HTTP ...[truncated 1009 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the MX_API_URL override if custom API origins are not required.
  2. Otherwise, parse the configured URL and enforce an exact allowlist:
    • Scheme must be https.
    • Hostname must be exactly mkapi2.dfcfs.com.
    • Port must be the expected HTTPS port.
    • User-information components must be rejected.
    • The normalized base path must be validated.
  3. Disable automatic redirects with allow_redirects=False, or validate every redirect target before following it.
  4. Attach MX_APIKEY only after destination validation succeeds.
  5. Fail closed when the URL is malformed or outside the approved origin.
  6. Add tests covering HTTP URLs, lookalike domains, embedded credentials, alternate ports, subdomains, and cross-origin redirects.
  7. Update the documentation so that its network-security claims accurately match the implementation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mx_stock_simulator.py:17
Finding

Sensitive simulated-account responses are automatically persisted in plaintext

Content
View full analysis

Vulnerability Details

File Location: scripts/mx_stock_simulator.py, lines 17–18 and 26–49
Vulnerability Type: Insecure storage of sensitive financial data
Risk Level: Medium

Vulnerable Code

python
# Output directory configuration
OUTPUT_DIR = '/root/.openclaw/workspace/mx_data/output'
PREFIX = 'mx_stock_simulator_'

def ensure_output_dir():
    """Ensure that the output directory exists."""
    if not os.path.exists(OUTPUT_DIR):
        os.makedirs(OUTPUT_DIR, exist_ok=True)

def save_result(query, text, data):
    """Save results to files."""
    ensure_output_dir()
    safe_query = query.replace(' ', '_')[:50]

    # Save formatted text
    txt_file = os.path.join(OUTPUT_DIR, f"{PREFIX}{safe_query}.txt")
    with open(txt_file, 'w', encoding='utf-8') as f:
        f.write(text)

    # Save the raw JSON response
    json_file = os.path.join(OUTPUT_DIR, f"{PREFIX}{safe_query}.json")
    with open(json_file, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

    return txt_file, json_file

The function is invoked after holdings, balance, order, cancellation, and trade operations in scripts/mx_stock_simulator.py, lines 309–357.

Similar default persistence is also present in:

  • scripts/mx_self_select.py, lines 146–175
  • scripts/mx_data.py, lines 302–327 and 359–368
  • scripts/mx_search.py, lines 166–190
  • scripts/mx_select_stock.py, lines 213–254

Technical Analysis

The simulator automatically writes formatted output and complete raw API responses to a fixed workspace directory. Persistence is not opt-in, and the script does not explicitly set restrictive directory or file permissions. It also provides no retention limit, cleanup mechanism, or warning before saving the data.

Depending on the requested operation, the files can contain holdings, balances, orders, transaction results, stock identifiers, quantities, pr ...[truncated 1529 chars]

Remediation
View remediation

Remediation Suggestions

  1. Make file persistence opt-in through an explicit option such as --save.
  2. Default to displaying results in the terminal without retaining raw responses.
  3. If storage is requested:
    • Create the output directory with mode 0700.
    • Create files with mode 0600.
    • Refuse to use symlinked output paths.
    • Use a user-specific private data directory rather than a shared fixed workspace.
  4. Avoid saving raw JSON unless explicitly requested, and minimize saved fields to those necessary for the user's task.
  5. Add configurable retention and secure deletion or cleanup controls.
  6. Inform the user before storing holdings, balances, orders, watchlists, or other account-related information.
  7. Apply the same controls consistently to mx_self_select.py, mx_data.py, mx_search.py, and mx_select_stock.py.
  8. Document the storage location, retained fields, permissions, retention period, and deletion procedure in SKILL.md.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (51)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/mx_self_select.py (reported line 62)May include surrounding context.

python
}
    
    try:
        response = requests.post(QUERY_URL, headers=headers, json={}, timeout=30)
        response.raise_for_status()
        return response.json()
    except Exception as e:

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/mx_self_select.py (reported line 81)May include surrounding context.

python
}
    
    try:
        response = requests.post(MANAGE_URL, headers=headers, json=data, timeout=30)
        response.raise_for_status()
        return response.json()
    except Exception as e:

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

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The request destination is derived from the MX_API_URL environment variable and used directly in requests.post while sending the API key in headers. If an attacker can influence the runtime environment or deployment config, they can redirect traffic to an attacker-controlled host and exfiltrate the credential and trading payloads. In a trading skill, this is more dangerous because requests include account actions such as buy, sell, and cancel operations.

Content

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

python
}
    
    try:
        response = requests.post(url, headers=headers, json=payload, timeout=30)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

There is a clear description-to-code mismatch. The declared purpose describes an entire 'mx-skills-suite' with five distinct financial subskills covering data lookup, information search, stock selection, watchlist management, and simulated trading. However, the provided code chunk is only for mx_data.py, which implements a single financial data query client against an Eastmoney API. It does not contain functionality for searching news/announcements/reports/policy, stock recommendation/filtering, self-select watchlist CRUD, or simulated trading operations such as holdings, buy/sell, cancel orders, or funds management. Additionally, the code exports results to local Excel/TXT/JSON files, which is behavior not reflected in the declared description. Because the declared description materially overstates the implemented capabilities of this code chunk, this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
83% confidence
Finding

The script reads credentials from a repository-adjacent .env file, which increases the risk of accidental secret exposure through source control, packaging, permissive filesystem access, or reuse across tools. In an agent/workspace environment, local files may be more broadly accessible than intended, making this more dangerous than using only process-injected secrets.

Content

Scanner excerpt · scripts/mx_self_select.py (reported line 33)May include surrounding context.

python
apikey = os.environ.get("MX_APIKEY", "")
    if not apikey:
        # 尝试从.env文件读取
        env_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env")
        if os.path.exists(env_file):
            try:
                with open(env_file, "r") as f:

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The cancel intent always sends payload {'type': 'all'}, causing a blanket cancel-all operation with no confirmation, preview, or order selection. A loosely phrased user request or mistaken intent classification could revoke every pending order immediately. In the context of a trading simulator, this is still a security-relevant unsafe action because it performs sensitive account state changes without explicit user consent safeguards.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Buy and sell requests are executed immediately after lightweight parsing of free-form text, without a confirmation step, order preview, or sanity checks on price and quantity. Misparsed inputs, prompt injection through upstream orchestration, or simple user mistakes could place unintended trades. The skill context increases risk because this code directly triggers trade endpoints, making unsafe automation of sensitive actions materially dangerous even if the account is a simulator.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill metadata declares network use and environment-based authentication, but it does not define any explicit tool scope such as allowed-tools or permissions. In an agent environment, missing scope boundaries can let the skill run with broader file, environment, or network access than users would reasonably expect, increasing the blast radius if the skill or a downstream prompt is abused.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger list includes broad, everyday financial phrases such as stock info, market queries, and portfolio-related terms, which can cause unintended activation in unrelated conversations. In a skill that can reach external APIs and potentially manage watchlists or simulated trades, accidental invocation can expose data, send requests, or steer user workflows without clear intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation instructs users to send arbitrary natural-language queries to a third-party remote API but provides no warning that prompts may contain sensitive financial, personal, or proprietary information. In an agent skill context, users may naturally include portfolio details, watchlists, or trading intent in free-form queries, causing unintended external disclosure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The curl example demonstrates direct transmission of a query and API key to an external service. While expected for API usage, the absence of any privacy or secret-handling warning makes this dangerous in a skill users may copy-paste, especially when financial queries could contain confidential trading or portfolio information.

Content

Scanner excerpt · references/mx-data.md (reported line 18)May include surrounding context.

示例

bash
curl -X POST 'https://mkapi2.dfcfs.com/finskillshub/api/claw/query' \
  --header 'Content-Type: application/json' \
  --header 'apikey: YOUR_API_KEY' \
  --data '{"toolQuery": "东方财富最新价"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The Python example performs a live POST request to an external endpoint with user-controlled natural-language content and an API key. In this financial skill context, that can transmit sensitive investment-related data off-platform without any minimization, consent, or warning, and may also expose credentials through surrounding application logging or debugging.

Content

Scanner excerpt · references/mx-data.md (reported line 42)May include surrounding context.

"apikey": os.getenv("MX_APIKEY") } data = {"toolQuery": "东方财富最新价"} response = requests.post(url, headers=headers, json=data, timeout=30) result = response.json()

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation instructs sending user-provided search queries to a third-party remote API but provides no user-facing disclosure, consent, or privacy warning. In a financial assistant context, queries may contain sensitive investment interests, holdings, or strategy information, so silent transmission can expose private user data to an external service.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The curl example explicitly sends a user query and API credential to a remote Eastmoney endpoint. This is not inherently malicious, but in a skill handling financial research, outbound transmission can leak sensitive interests or proprietary analysis topics if used without adequate transparency and controls.

Content

Scanner excerpt · references/mx-search.md (reported line 18)May include surrounding context.

示例

bash
curl -X POST 'https://mkapi2.dfcfs.com/finskillshub/api/claw/news-search' \
  --header 'Content-Type: application/json' \
  --header 'apikey: YOUR_API_KEY' \
  --data '{"query": "立讯精密的资讯"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The example code performs an outbound POST request containing the user's query and an API key to an external endpoint. While expected for this skill's functionality, it still represents real external data exfiltration risk if users are not informed or if sensitive financial prompts are forwarded without filtering.

Content

Scanner excerpt · references/mx-search.md (reported line 42)May include surrounding context.

"apikey": os.getenv("MX_APIKEY") } data = {"query": "格力电器最新研报"} response = requests.post(url, headers=headers, json=data, timeout=30) result = response.json()

text

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/mx-select-stock.md (reported line 14)May include surrounding context.

示例

bash
curl -X POST 'https://mkapi2.dfcfs.com/finskillshub/api/claw/stock-screen' \
  --header 'Content-Type: application/json' \
  --header 'apikey: YOUR_API_KEY' \
  --data '{"keyword": "今日涨幅2%的股票", "pageNo": 1, "pageSize": 20}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manage endpoint performs state-changing operations on a user's authenticated watchlist, but the documentation presents add/delete actions without any warning that account data will be modified. In an agent setting, this omission increases the risk of unintended or overly broad execution of user instructions because the action looks similar to a harmless query rather than an authenticated account mutation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/mx-selfselect.md (reported line 38)May include surrounding context.

md
}

# 查询自选股
response = requests.post(
    "https://mkapi2.dfcfs.com/finskillshub/api/claw/self-select/get",
    headers=headers, json={}, timeout=30
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · references/mx-selfselect.md (reported line 38)May include surrounding context.

md
}

# 查询自选股
response = requests.post(
    "https://mkapi2.dfcfs.com/finskillshub/api/claw/self-select/get",
    headers=headers, json={}, timeout=30
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
72% confidence
Finding

This duplicate finding targets the same manage POST call that sends a natural-language add command to an external service. The risk is not mere network use but the combination of external transmission, free-form command text, and authenticated state change on a user account.

Content

Scanner excerpt · references/mx-selfselect.md (reported line 44)May include surrounding context.

md
)

# 添加自选股
response = requests.post(
    "https://mkapi2.dfcfs.com/finskillshub/api/claw/self-select/manage",
    headers=headers, json={"query": "把贵州茅台添加到我的自选股列表"}, timeout=30
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
72% confidence
Finding

This duplicate finding targets the same manage POST call that sends a natural-language add command to an external service. The risk is not mere network use but the combination of external transmission, free-form command text, and authenticated state change on a user account.

Content

Scanner excerpt · references/mx-selfselect.md (reported line 44)May include surrounding context.

md
)

# 添加自选股
response = requests.post(
    "https://mkapi2.dfcfs.com/finskillshub/api/claw/self-select/manage",
    headers=headers, json={"query": "把贵州茅台添加到我的自选股列表"}, timeout=30
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
72% confidence
Finding

This duplicate finding covers the same manage POST call for deleting an item from the watchlist. The contextual danger comes from allowing externalized natural-language deletion commands against user account data without explicit safeguards described in the skill.

Content

Scanner excerpt · references/mx-selfselect.md (reported line 50)May include surrounding context.

md
)

# 删除自选股
response = requests.post(
    "https://mkapi2.dfcfs.com/finskillshub/api/claw/self-select/manage",
    headers=headers, json={"query": "把贵州茅台从我的自选股列表删除"}, timeout=30
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
72% confidence
Finding

This duplicate finding covers the same manage POST call for deleting an item from the watchlist. The contextual danger comes from allowing externalized natural-language deletion commands against user account data without explicit safeguards described in the skill.

Content

Scanner excerpt · references/mx-selfselect.md (reported line 50)May include surrounding context.

md
)

# 删除自选股
response = requests.post(
    "https://mkapi2.dfcfs.com/finskillshub/api/claw/self-select/manage",
    headers=headers, json={"query": "把贵州茅台从我的自选股列表删除"}, timeout=30
)

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · references/mx-stock-simulator.md (reported line 35)May include surrounding context.

  • Body: {}
bash
curl -X POST "https://mkapi2.dfcfs.com/finskillshub/api/claw/mockTrading/positions" \
  -H "apikey: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The document describes buy/sell and cancel operations that can change a user's simulated portfolio state, including examples for market-price trades and bulk cancellation, but it does not include an explicit warning, confirmation requirement, or safe-use guidance for account-impacting actions. In an agent setting, this increases the chance that a model or user invokes destructive or unintended actions without understanding the consequences, especially because the same skill also supports authenticated API calls.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.