Back to skill

Security audit

a-share-analysis

Security checks for vulnerabilities and agentic risk

Overview

This A-share stock analysis skill is not clearly malicious, but it needs Review because it produces actionable investment recommendations while writing persistent agent memory and report files from insufficiently constrained inputs.

Review before installing. Use only in an isolated workspace, treat all outputs as informational rather than financial advice, validate stock codes as six digits, avoid the rm -rf cleanup examples, and do not enable Firecrawl or provide an API key unless you accept third-party network calls and local plaintext credential storage.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T02 · Agent Memory Poisoning

Error
Location
scripts/memory_store.py:35
Finding
Persistent Agent Memory Injection Through Unsanitized Stock Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/memory_store.py:35-44, 52-85, 143-163, 165-203`; data originates from `scripts/analyze_stock_pro.py:204-228` **Vulnerability Type**: Persistent prompt and state injection **Risk Level**: High ### Vulnerable Code ```python def __init__(self, workspace_path: str = None): # 获取工作区路径 if workspace_path is None: workspace_path = os.path.expanduser("~/.openclaw/workspace") self.workspace_path = workspace_path self.memory_dir = os.path.join(workspace_path, "memory") self.a_share_memory_dir = os.path.join(self.memory_dir, "a-share") self.session_state_path = os.path.join(workspace_path, "SESSION-STATE.md") self.memory_md_path = os.path.join(workspace_path, "MEMORY.md") # 确保目录存在 os.makedirs(self.a_share_memory_dir, exist_ok=True) ``` ```python def store_analysis(self, analysis_data: Dict) -> str: """存储一次分析记录""" stock_code = analysis_data.get('stock_code', 'unknown') stock_name = analysis_data.get('stock_name', '未知股票') timestamp = datetime.now() record = { "timestamp": timestamp.isoformat(), "date": timestamp.strftime("%Y-%m-%d"), "time": timestamp.strftime("%H:%M:%S"), "stock_code": stock_code, "stock_name": stock_name, "price": analysis_data.get('price'), "change_percent": analysis_data.get('change_percent'), "technical_signal": analysis_data.get('technical', {}).get('signal', 'unknown'), "sentiment": analysis_data.get('sentiment', {}).get('overall_sentiment', 'unknown'), "recommendation": analysis_data.get('recommendation', 'unknown'), "key_points": analysis_data.get('key_points', []) } today_file = self._get_today_file() self._append_to_daily_log(today_file, record) stock_memory_file = os.path.join(self.a_share_memory_dir, f"{stock_code}.json") self._append_to_stock_memory(stock_memory_file, record) self._update_session_state( ...[truncated 2534 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store stock-analysis history in an application-specific directory that is not automatically loaded as Agent context. 2. Do not write application records into `SESSION-STATE.md` or `MEMORY.md` by default. 3. Require explicit user consent before enabling persistent history. 4. Validate stock codes against a strict allowlist such as `^[0-9]{6}$`. 5. Restrict stock names to a single line and a reasonable length. 6. Escape Markdown control characters and remove carriage returns, line feeds, and instruction-like blocks before rendering. 7. Keep authoritative data in structured JSON or a database and generate display-only Markdown from validated fields. 8. Mark imported or user-controlled text as untrusted data when it is presented to an Agent. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_report_pro.py:419
Finding
Arbitrary File Write Through Unsanitized Stock Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_report_pro.py:419-435`; equivalent path construction is present in `scripts/generate_report_commercial.py:100-116`, `scripts/generate_report_detailed.py:873-889`, `scripts/generate_pdf_report.py:166-174`, and `scripts/memory_store.py:77, 119-138` **Vulnerability Type**: Path traversal and arbitrary file write **Risk Level**: High ### Vulnerable Code ```python def save_report(self, report: str, stock_code: str, stock_name: str) -> str: """保存报告(按股票代码分类存储)""" timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") # 创建股票代码二级目录 stock_dir = os.path.join(self.output_dir, stock_code) os.makedirs(stock_dir, exist_ok=True) # 保存报告到股票代码目录 filename = f"{stock_code}_{stock_name}_{timestamp}_PRO.md" filepath = os.path.join(stock_dir, filename) with open(filepath, "w", encoding="utf-8") as f: f.write(report) logger.info(f"报告已保存:{filepath}") return filepath ``` The memory implementation constructs another write path from the same unvalidated identifier: ```python stock_memory_file = os.path.join( self.a_share_memory_dir, f"{stock_code}.json" ) self._append_to_stock_memory(stock_memory_file, record) ``` ### Technical Analysis `stock_code` and `stock_name` originate from positional command-line arguments and batch files, but they are never constrained to expected stock-code or filename formats. Passing an absolute path to `os.path.join` causes Python to discard the preceding base directory. Traversal components can likewise escape the intended report or memory directory. The same untrusted stock code is used both as a directory component and as part of the output filename. The report filename contains a timestamp, which limits deterministic replacement of an existing report. The memory JSON filename is stable and can overwrite an existing `.json` file at an escaped location if the process has permission. ### Attack Path 1. An attacker cont ...[truncated 1045 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject any stock code that does not match `^[0-9]{6}$`. 2. Restrict stock names to approved Unicode letters, digits, spaces, and a small set of safe punctuation. 3. Remove `/`, `\`, null bytes, drive prefixes, and `.` or `..` path components from all filename inputs. 4. Resolve the candidate path with `Path.resolve()` and verify it is a descendant of the resolved output directory before writing. 5. Generate server-controlled filenames rather than incorporating raw user input. 6. Open new report files with exclusive creation mode where replacement is unnecessary. 7. Apply the same validation centrally to Markdown, PDF, memory, cache, and batch-analysis output paths. 8. Add automated tests for absolute paths, Windows drive paths, UNC paths, `../` traversal, and encoded separator variants. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL_ENHANCED.md:151
Finding
Unpinned Globally Installed Firecrawl CLI Is Executed by the Skill<![CDATA[ ## Vulnerability Details **File Location**: `SKILL_ENHANCED.md:151-158`; executable use at `scripts/fetch_news_sentiment.py:45-79`; the same global installation instruction also appears in `README.md:300` **Vulnerability Type**: Unsafe third-party dependency installation and execution **Risk Level**: Medium ### Vulnerable Code and Instructions ```bash # 安装 Firecrawl CLI npm install -g firecrawl-cli # 登录认证 firecrawl login --browser # 检查状态 firecrawl --status ``` The unpinned executable is then invoked by the Skill: ```python def _check_firecrawl(self) -> bool: """检查 Firecrawl 是否可用""" try: result = subprocess.run( ["firecrawl", "--status"], capture_output=True, text=True, timeout=10 ) return result.returncode == 0 except Exception as e: logger.warning(f"Firecrawl 检查失败:{e}") return False ``` ```python cmd = [ "firecrawl", "search", query, "--limit", str(limit), "--sources", "news", "--tbs", "qdr:d", "--json" ] result = subprocess.run( cmd, capture_output=True, text=True, timeout=30, encoding='utf-8' ) ``` ### Technical Analysis The documentation directs users to globally install the latest available version of `firecrawl-cli`. No exact version, package integrity value, lockfile, or reviewed artifact is specified. npm packages can run lifecycle scripts during installation, and the resulting globally resolved executable is repeatedly launched by the Skill. The subprocess argument list prevents shell metacharacter injection through the query itself. The primary issue is dependency trust and mutability rather than command injection. ### Attack Path 1. A user follows the Skill documentation and runs `npm install -g firecrawl-cli`. 2. npm resolves the currently published package and dependencies rather than a reviewed, locked dependency graph. 3. A compromised release or transitive dependency executes code durin ...[truncated 694 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin Firecrawl to an exact reviewed version. 2. Maintain a project-local `package-lock.json` or equivalent lockfile. 3. Verify package integrity and publisher identity before installation. 4. Avoid global npm installation; use a project-local dependency and a fixed executable path. 5. Disable npm lifecycle scripts where compatible, or review all required lifecycle scripts before allowing them. 6. Document the official package source and expected checksums. 7. Run the CLI in a constrained environment with only the network and filesystem access required for news searches. 8. Reassess and update the pinned dependency through a controlled review process. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_realtime_data.py:35
Finding
Market Data Used for Investment Analysis Is Retrieved Over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_realtime_data.py:35-61, 112-117`; additional plaintext endpoints occur in `scripts/fetch_fundamental_data.py:22,49`, `scripts/fetch_sentiment_data.py:22,49,88,128`, and `scripts/fetch_technical_indicators_free.py:23-24,56` **Vulnerability Type**: Missing transport authentication and integrity protection **Risk Level**: Medium ### Vulnerable Code ```python class AShareRealTimeFetcher: """A 股实时数据获取器""" # 新浪财经 API XINHUA_URL = "http://hq.sinajs.cn/list=" def __init__(self): self.session = requests.Session() self.session.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "http://finance.sina.com.cn/" }) ``` ```python def fetch_stock_data(self, stock_code: str) -> Optional[Dict]: """获取股票实时数据(带重试)""" for attempt in range(MAX_RETRIES): try: if stock_code.startswith('6') or stock_code.startswith('5'): prefix = 'sh' else: prefix = 'sz' url = f"{self.XINHUA_URL}{prefix}{stock_code}" response = self.session.get(url, timeout=TIMEOUT) response.encoding = 'gb18030' data = response.text logger.info(f"API 返回:{data[:200]}") if data and '=' in data: content = data.split('="')[1].strip('"') parts = content.split(',') ``` ```python def fetch_index_data(self, index_code: str) -> Optional[Dict]: """获取指数实时数据""" try: url = f"{self.XINHUA_URL}{index_code}" response = self.session.get(url, timeout=TIMEOUT) response.encoding = 'gb18030' data = response.text ``` ### Technical Analysis HTTP does not authenticate the remote server and does not protect response integrity. A network-positioned attacker can observe or alter stock codes and returned prices. The parser only verifies basic ...[truncated 1255 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace all market-data URLs with provider-supported HTTPS endpoints. 2. Do not silently fall back from HTTPS to HTTP. 3. Reject redirects whose destination uses an insecure scheme. 4. Keep TLS certificate verification enabled and use an up-to-date trust store. 5. Validate response schemas, stock identifiers, timestamps, numeric ranges, and required fields before using data. 6. Consider comparing critical investment data against a second authenticated source. 7. Mark data unavailable and fail closed when authenticated transport cannot be established. 8. Avoid persisting recommendations generated from data that failed integrity or freshness checks. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/firecrawl_auto_auth.py:137
Finding
Firecrawl API Key Is Persisted in a Plaintext Configuration File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/firecrawl_auto_auth.py:137-150` **Vulnerability Type**: Insecure local credential storage **Risk Level**: Medium ### Vulnerable Code ```python def _set_api_key(self, api_key: str) -> bool: """设置 API 密钥""" try: # 创建配置目录 self.config_dir.mkdir(exist_ok=True) # 写入配置 config = { "apiKey": api_key, "apiUrl": "https://api.firecrawl.dev" } with open(self.config_file, "w") as f: json.dump(config, f, indent=2) logger.info(f"API 密钥已保存至 {self.config_file}") # 验证 status = self.check_status() return status.get("authenticated", False) except Exception as e: logger.error(f"设置 API 密钥失败:{e}") return False ``` ### Technical Analysis The automatic authentication routine copies `FIRECRAWL_API_KEY` from the process environment into `~/.firecrawl/config.json`. The directory and file are created without explicitly restrictive permissions, so their accessibility depends on the host operating system and current umask. The key is not intentionally transmitted to an attacker-controlled destination in the reviewed code. The flagged documentation files—`USAGE.md`, `ENHANCEMENT_REPORT_V2.md`, and `FINAL_COMPLETION_REPORT.md`—contain placeholder API-key setup commands, not confirmed exfiltration logic. The security issue is local plaintext persistence. ### Attack Path 1. A user places a valid Firecrawl API key in the environment and runs automatic authentication. 2. `_set_api_key` serializes the key into `~/.firecrawl/config.json`. 3. On a host with permissive default permissions, another local account, indexing process, backup system, or unrelated application reads the configuration file. 4. The exposed key is reused to consume API credits or access the victim's Firecrawl account capabilities. ### Impact Assessment The obtainable privilege is limited to whatever access and quo ...[truncated 266 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer the operating system's credential manager or keychain instead of a plaintext JSON file. 2. If file storage is unavoidable, create `~/.firecrawl` with mode `0700` and the configuration file with mode `0600` on POSIX systems. 3. Verify and correct permissions after creating or replacing the file. 4. Use atomic creation with restrictive permissions to avoid a temporarily exposed file. 5. Clearly disclose that automatic authentication persists the key. 6. Offer a non-persistent mode that leaves the key only in the process environment. 7. Never log the key or include it in diagnostic output. 8. Provide key revocation and rotation guidance. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (76)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
### 清理报告
```bash
# 删除某支股票的所有报告
rm -rf a-share-reports/600519/

# 删除所有报告
rm -rf a-share-reports/*
Confidence
97% confidence
Finding
The documentation provides a destructive shell command to recursively and forcibly delete a stock's report directory. In a tool-using agent or inattentive user context, such commands can be executed without validation, causing permanent data loss; if the path is parameterized elsewhere, the risk can expand to unintended directories.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
rm -rf a-share-reports/600519/

# 删除所有报告
rm -rf a-share-reports/*
```

---
Confidence
99% confidence
Finding
The command `rm -rf a-share-reports/*` can wipe all generated reports in one action and is especially dangerous in environments where commands may be copied verbatim or executed by an automation agent. Wildcard-based recursive deletion increases blast radius and can become catastrophic if the base path is changed, empty, or resolved unexpectedly.

Natural-Language Policy Violations

High
Confidence
97% confidence
Finding
The skill explicitly instructs the agent to provide concrete investment recommendations like buy/hold/sell as part of normal operation, without requiring user opt-in, suitability checks, or policy gating. That is dangerous because it can lead to actionable financial advice being generated as if it were endorsed workflow behavior, increasing legal, safety, and misuse risk.

Natural-Language Policy Violations

High
Confidence
98% confidence
Finding
The example scenario normalizes answering 'Is Wuliangye worth buying?' by performing analysis and then giving a direct investment recommendation. This is especially risky because examples strongly shape agent behavior, making it more likely the system will provide prescriptive financial advice in live interactions without adequate safeguards.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The file presents all operational guidance and report descriptions exclusively in Chinese, which may force a specific language for users without opt-in. The policy allows locale constraints when they are explicitly justified or when the user is offered a choice, neither of which is stated here.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The markdown repeatedly specifies that report content includes fixed Chinese/English output, such as '中英文标题', and later '评级标签(中英文)' and English section headers in examples. This imposes a language/locale format by default without indicating that users can choose or opt in to the language used.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The markdown instructs users that they can delete reports by stock code, which is a destructive action affecting user data. There is no accompanying caution to verify targets or back up data before deletion, so the description lacks an appropriate user warning for a potentially irreversible operation.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The document states that analysis runs automatically write persistent artifacts such as daily memory files, per-stock JSON history, SESSION-STATE updates, and MEMORY archives, but it does not mention any user consent, warning, or opt-out. In an agent skill context, silent persistence can expose sensitive prompts, analysis targets, or workflow context to disk and create privacy and data-retention risks that users may not expect.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The usage section provides direct run commands but omits a warning that executing them will save reports and memory artifacts to disk. This increases the chance that a user runs the tool in a sensitive environment and unintentionally leaves persistent local records containing stock queries, timestamps, recommendations, and session context.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This markdown file presents all instructions, usage guidance, warnings, and examples exclusively in Chinese. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The document consistently presents all instructions, examples, warnings, and usage information only in Chinese. Under the policy criteria, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not stated here.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The entire skill document is written in Chinese and presents usage instructions, warnings, and outputs solely in that language, with no indication that users may choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README states that the skill uses external data sources including 新浪财经 API, 东方财富 API, and optional Firecrawl web scraping, but it does not clearly disclose that running the skill sends requests to third-party services and may transmit queried stock symbols, timing, or scraped content externally. This is dangerous from a privacy and network-trust perspective, especially in controlled or enterprise environments where outbound connections and third-party processing require explicit disclosure and approval.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The README explicitly advertises '历史记忆 - Elite Memory 存储' and later documents persistent storage under workspace memory paths, but it does not clearly warn users that analysis history will be retained locally over time. This creates a privacy and data-governance risk because stock interests, analysis history, and generated reports may reveal sensitive user behavior or business research activity and remain on disk unexpectedly.

Session Persistence

Medium
Category
Rogue Agent
Content
cp docs/* ~/.openclaw/workspace/a-share-analysis/

# 3. 创建目录
mkdir -p ~/.openclaw/workspace/a-share-reports
mkdir -p ~/.openclaw/workspace/memory/a-share

# 4. 安装依赖
Confidence
85% confidence
Finding
The documented installation creates persistent directories for reports and memory under ~/.openclaw/workspace, indicating session/state persistence across runs. Persistent local storage is risky when not clearly bounded because generated reports and per-stock memory files can accumulate sensitive research artifacts, and other local users/processes may access them depending on host permissions.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The document includes irreversible deletion commands (`rm -rf`) as ready-to-run examples without a strong warning, confirmation step, or safer alternative. In agent or copy-paste-driven workflows, users may execute these commands directly and unintentionally delete report data or broader filesystem contents if paths are modified or expanded incorrectly.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The skill description is broad enough to activate on generic stock-analysis or investment-advice requests, which can cause the agent to route users into a recommendation-producing workflow without clear limits. In this context, overbroad triggering increases the chance of unqualified financial guidance being provided when the user only asked for neutral market information.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The skill description is scoped to very broad stock-analysis requests and includes generic triggers like investment advice, market quotes, technical analysis, and comprehensive reports. In an agentic environment, this can cause over-invocation on loosely related finance prompts, increasing the chance of unnecessary tool use, external data access, and generation of regulated or high-risk financial guidance without clear user intent boundaries.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly stores analysis records and historical summaries in persistent local files, but it does not clearly warn users up front that their requests, stock interests, recommendations, and derived analysis may be written to disk. This creates a privacy and data-governance risk because sensitive user behavior and financial interests could be retained unexpectedly and later exposed to other agents, users, or local system access.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
SQP-3 applies to all file types and covers language or locale policy violations. This report presents all user-facing instructions and status information only in Chinese, with no opt-in, alternative language, or documented region-specific justification, which can amount to forcing a specific language.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The document title and all user-facing instructions are presented exclusively in Chinese, indicating a fixed language experience. There is no indication that users can opt into another language or that the Chinese-only constraint is required for a region-specific compliance reason.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation explicitly describes persistent storage of analysis history and session state, including per-stock history and active context, but does not explain retention, access controls, or privacy implications. In an agent skill context, long-term memory can unintentionally retain sensitive prompts, user interests, strategy notes, or operational data that may later be exposed, over-retained, or reused beyond user expectations.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The documentation instructs users to set a Firecrawl API key and references automatic authentication, but it does not warn that the credential is sensitive or advise secure handling. In a skill ecosystem, users may paste secrets into logs, shared terminals, screenshots, shell history, or checked-in config, increasing the chance of credential leakage and unauthorized API use.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring and throughout the file use Chinese-only labels and A-share-specific terminology, presenting the skill as fixed to a specific language/locale. Under the policy, locale or language constraints should either be user-selectable or clearly justified as a region-specific tool.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
User-facing strings, help text, status messages, and the program description are consistently hardcoded in Chinese throughout the file. This enforces a specific language/locale without any visible option for user selection or documented justification for a locale restriction.

Static analysis

No suspicious patterns detected.