T09 · Insecure Skill Coding Practices
- Location
scripts/analyze_stocks.py:63- Finding
Excessive Credential Access and Unrestricted Environment Disclosure to an External Skill
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/analyze_stocks.py:63Excessive Credential Access and Unrestricted Environment Disclosure to an External Skill
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.
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 均线'],
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.
capture_output=True,
text=True,
timeout=60,
env={**os.environ, 'EM_API_KEY': em_api_key}
)
# 解析输出获取文件路径
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.
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 均线'],
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.
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 均线'],
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.
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.
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.
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.
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.
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 calls execute external commands. Without careful input validation, this enables command injection.
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,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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,
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
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,
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.
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 calls execute external commands. Without careful input validation, this enables command injection.
try:
# 调用妙想数据脚本
result = subprocess.run(
['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py', '--query', query],
capture_output=True,
text=True,
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
try:
# 调用妙想数据脚本
result = subprocess.run(
['python3', '/root/.openclaw/workspace/skills/mx-finance-data/scripts/get_data.py', '--query', query],
capture_output=True,
text=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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,
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.
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 calls execute external commands. Without careful input validation, this enables command injection.
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,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
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,