Back to skill

Security audit

Stock Entry Analyzer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a stock-analysis tool, but some bundled executable scripts silently use a finance API credential and pass the full runtime environment to another skill.

Install only if you are comfortable with a stock-analysis skill that can run local scripts and depend on other finance-data skills. Review or remove the legacy scripts that read the EastMoney credential vault and pass the full environment to mx-finance-data, and treat all buy/sell outputs as informational rather than personal financial 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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/analyze_stocks.py:63
Finding
Excessive Credential Access and Unrestricted Environment Disclosure to an External Skill<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/analyze_stocks.py:63-84` - `scripts/analyze_stocks_v2.py:33-59` - `scripts/analyze_stocks_v3.py:98-119` - `scripts/analyze_stocks_v3_detailed.py:73-94` **Vulnerability Type**: Excessive credential access and sensitive environment disclosure across a Skill boundary **Risk Level**: Medium ### Vulnerable Code #### `scripts/analyze_stocks.py:63-84` ```python em_api_key = os.environ.get('EM_API_KEY', '') if not em_api_key: try: with open('/root/.openclaw/workspace/vault/credentials/eastmoney.json', 'r') as f: config = json.load(f) em_api_key = config.get('em_api_key', '') except: return None if not em_api_key: return None try: import subprocess env = {**os.environ, 'EM_API_KEY': em_api_key} result = subprocess.run( ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py', '--query', f'{code.replace(".HK", "")}.HK EMA 均线'], capture_output=True, text=True, timeout=30, env=env ) ``` #### `scripts/analyze_stocks_v2.py:33-59` ```python em_api_key = os.environ.get('EM_API_KEY', '') if not em_api_key: # 从配置文件读取 try: with open('/root/.openclaw/workspace/vault/credentials/eastmoney.json', 'r') as f: config = json.load(f) em_api_key = config.get('em_api_key', '') except: pass if not em_api_key: print("警告:未找到 EM_API_KEY,使用 stock-price-query 作为备用", file=sys.stderr) return get_stock_data_tencent() # 构建查询语句 codes = [s['code'] for s in STOCKS] query = f"{','.join(codes)} 实时行情 涨跌幅 成交量" try: # 调用妙想数据脚本 result = subprocess.run( ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py', '--query', query], capture_output=True, text=True, timeout=60, env={**os.environ, 'EM_API_KEY': em_api_key} ) ``` #### `scripts/analyze_stocks_v3.py:9 ...[truncated 4374 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Remove automatic credential-vault discovery.** Do not read credentials directly from `/root/.openclaw/workspace/vault/credentials/`. Require the caller or platform to inject `EM_API_KEY` through an explicitly authorized secret-management mechanism. 2. **Construct a minimal subprocess environment.** Replace unrestricted environment copying with an allowlist: ```python child_env = { 'PATH': os.environ.get('PATH', ''), 'LANG': os.environ.get('LANG', 'C.UTF-8'), 'EM_API_KEY': em_api_key, } ``` Include only variables that the child process demonstrably requires. 3. **Avoid privileged absolute paths.** Make external Skill and output locations configurable or resolve them through an approved Skill registry. Do not assume execution under `/root`. 4. **Verify the external Skill.** Pin an audited version of `mx-finance-data`, verify its integrity before execution, and document its permitted network destinations and credential-handling behavior. 5. **Constrain the API credential.** Use a dedicated, narrowly scoped API key with rate limits, usage monitoring, rotation, and revocation support. 6. **Fail closed when credentials are unavailable.** Return a clear data-source error rather than searching unrelated filesystem locations for credentials. 7. **Validate child-process outputs.** Validate and constrain any Excel path returned by the external process before opening it, ensuring that it refers to an expected directory and regular file. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (47)

Env Variable Harvesting

High
Category
Data Exfiltration
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
Confidence
84% confidence
Finding
The code forwards the full parent process environment into a child process while also injecting a sensitive API credential. In a skill-based execution environment, this broad inheritance can unnecessarily expose unrelated secrets, tokens, and runtime context to another script, increasing the blast radius if that downstream component is compromised, overly verbose, or logs its environment.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
capture_output=True,
            text=True,
            timeout=60,
            env={**os.environ, 'EM_API_KEY': em_api_key}
        )
        
        # 解析输出获取文件路径
Confidence
93% confidence
Finding
The child process inherits the full parent environment via os.environ while also injecting EM_API_KEY. In an agent or skill ecosystem, broad environment forwarding can expose unrelated secrets, tokens, proxies, and runtime credentials to helper scripts, significantly enlarging the blast radius if those scripts are compromised or behave unexpectedly.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
Confidence
88% confidence
Finding
The script reads a secret API key from environment variables or a credential file and then constructs a child-process environment by copying the entire process environment. In a skill ecosystem where downstream scripts may be less trusted, this unnecessarily exposes credentials and other environment secrets to external code, increasing the risk of secret leakage.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
Confidence
91% confidence
Finding
The skill explicitly harvests a secret from the runtime environment or a vault file and forwards it to another script. In a skill/plugin setting, this is dangerous because it normalizes credential access and propagation across components; if the downstream script is modified, compromised, or overly verbose in logging/errors, the secret can be exposed or abused for unauthorized API access.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The description, trigger phrases, examples, and output templates are consistently presented only in Chinese, and there is no indication that users may choose another language or that the skill is intentionally restricted to a Chinese-language audience. This can violate a language/locale policy requiring user choice or explicit justification for locale constraints.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger phrases are broad enough to activate on ordinary investment conversation, which can cause the skill to run unexpectedly and present authoritative-seeming financial recommendations when the user may not have explicitly requested this workflow. In an agent setting, overbroad activation increases the chance of unintended tool use, excessive data access, and misleading automated advice.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The skill description and threshold section state that the preferred BIAS entry range is 5%-15% and mark 2.14% as below that documented target. However, this example checklist and recommendation instead evaluate against a much narrower 0.6%-1.8% interval, creating a direct contradiction in the skill's own documentation about what counts as a valid entry signal.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The document provides specific trading thresholds and entry/exit rules that could be interpreted as actionable financial advice, yet it does not include any warning about investment risk, uncertainty, suitability, or the possibility of loss. In the context of an agent skill, users may over-trust this structured guidance and act on it as prescriptive advice, which increases the chance of financial harm from losses or inappropriate trading decisions.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This markdown file is entirely written as a prescriptive scoring/output reference in Chinese, including the required output template, with no indication that users may choose another language. Under the policy rules, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The module title and descriptive text are written entirely in Chinese, and the generated user-facing report strings throughout the file are also Chinese-only. This imposes a specific language on users without any opt-in or indication that the skill is intentionally region-specific for compliance or audience reasons.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
query_str = ",".join(codes)
    
    try:
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/stock-price-query/scripts/stock_query.py', query_str],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
query_str = ",".join(codes)
    
    try:
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/stock-price-query/scripts/stock_query.py', query_str],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'env' from os.environ.get (line 77, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
try:
        import subprocess
        env = {**os.environ, 'EM_API_KEY': em_api_key}
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py',
             '--query', f'{code.replace(".HK", "")}.HK EMA 均线'],
            capture_output=True,
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.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The docstring at L117-L122 states this function calculates a real EMA20 from historical K-line data, with fallback estimation. However, the implementation at L131-L146 does not retrieve historical series at all; it invokes the live quote script again and derives EMA20 from current price plus a guessed 20-day change extrapolated from 5-day change. This is an active contradiction between documentation and behavior, not merely missing detail.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script reads an API credential from a fixed sensitive file path without any explicit user-facing disclosure or consent. In an agent-skill context, silent credential access is dangerous because it can expand the skill's privileges beyond what a user expects and normalize undisclosed secret consumption.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        # 调用妙想数据脚本
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py', '--query', query],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'em_api_key' from os.environ.get (line 33, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
try:
        # 调用妙想数据脚本
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py', '--query', query],
            capture_output=True,
            text=True,
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.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
codes = [s['code'].replace('.HK', '').replace('.SZ', '').replace('.SH', '') for s in STOCKS]
    
    try:
        result = subprocess.run(
            ['python3', '/root/.openclaw/workspace/skills/stock-price-query/scripts/stock_query.py', ','.join(codes)],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The report states that the data source is the Eastmoney/Miaoxiang service even though the code can silently fall back to Tencent data. This can mislead users about provenance and trustworthiness of financial analysis, undermining auditability and causing decisions based on inaccurate assumptions about source quality and consistency.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The module docstring and all user-facing report content are written in Chinese, indicating the skill is designed to operate in a fixed language/locale. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which it is not here.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
query_str = ",".join(batch)
        
        try:
            result = subprocess.run(
                ['python3', '/root/.openclaw/workspace/skills/stock-price-query/scripts/stock_query.py', query_str],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
query_str = ",".join(batch)
        
        try:
            result = subprocess.run(
                ['python3', '/root/.openclaw/workspace/skills/stock-price-query/scripts/stock_query.py', query_str],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.