Back to skill

Security audit

hectorlee-volume-price-screener

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent A-share stock-screening toolkit, but it has unsafe pickle loading paths and broad finance/MCP/network behavior that users should review before installing.

Install only if you are comfortable with a Chinese-language A-share analysis tool that reads local market databases, sends stock codes/search terms to market-data providers, uses a local WorkBuddy MCP proxy, and may process positions files containing cost basis and share counts. Do not load third-party `.pkl` model files or run backtests against cache files you did not create and trust; the pickle loading issue should be fixed before use in shared or higher-risk environments.

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/ml_model.py:184
Finding
Arbitrary Code Execution Through Untrusted Pickle Model Deserialization<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ml_model.py:184-188`, invoked through `scripts/screener.py:339` and `scripts/screener.py:369-374`; an equivalent model-loading path exists in `scripts/portfolio_backtest.py:72-76` **Vulnerability Type**: Unsafe deserialization of a user-selected model file **Risk Level**: High ### Vulnerable Code `scripts/ml_model.py:184-188`: ```python def load_model(path: str) -> dict: import pickle with open(path, "rb") as f: return pickle.load(f) ``` `scripts/screener.py:339`: ```python ap.add_argument("--model", help="ML概率模型路径(.pkl),启用ML排序") ``` `scripts/screener.py:369-374`: ```python if args.model: try: from ml_model import load_model ml_model = load_model(args.model) m = ml_model.get("metrics", {}) print(f"{CYAN}ML模型已加载: {args.model}({m.get('backend','?')} AUC={m.get('auc','?')}){RESET}") ``` `scripts/portfolio_backtest.py:72-76`: ```python def add_ml_probs(samples: List[dict], model_path: str = MODEL_FILE) -> List[dict]: """批量计算 ML 上涨概率""" with open(model_path, "rb") as f: bundle = pickle.load(f) ``` ### Technical Analysis Python pickle is an executable object serialization format rather than a passive data format. A crafted pickle can define reduction operations that invoke attacker-selected Python callables during `pickle.load()`. Execution occurs before the application can inspect the returned model bundle or validate expected keys. The `screener.py --model` argument permits the caller to select the file passed directly to `pickle.load()`. No signature, trusted digest, ownership check, path restriction, or safe deserialization mechanism is applied. Catching exceptions around model loading does not mitigate the issue because a malicious reduction payload executes while deserialization is in progress. The same underlying issue exists in the portfolio backtest model-loading function. Although its command-line integration does no ...[truncated 1495 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace pickle with non-executable model formats: - Use XGBoost's JSON model format for XGBoost models. - Use a reviewed interchange format such as ONNX where appropriate. - Store model metadata and feature names separately as validated JSON. 2. Do not accept arbitrary pickle paths through `--model`. If legacy pickle support is unavoidable: - Restrict models to an application-owned directory. - Resolve the canonical path and reject files outside that directory. - Verify file ownership and reject group-writable or world-writable files. - Require a cryptographic signature or a trusted SHA-256 digest before loading. - Display an explicit warning that only locally generated, trusted models may be used. 3. Validate the deserialized bundle after authenticity verification: - Require an exact schema. - Verify the expected feature list and model backend. - Reject unknown fields and incompatible versions. 4. Add security regression tests confirming that unsigned, out-of-directory, or permission-unsafe model files are rejected before deserialization. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/backtest.py:50
Finding
Arbitrary Code Execution Through Automatically Trusted Pickle Cache<![CDATA[ ## Vulnerability Details **File Location**: `scripts/backtest.py:50-59`; repeated cache loads occur in `scripts/portfolio_backtest.py:63-67`, `scripts/portfolio_backtest.py:230-232`, and `scripts/portfolio_backtest.py:288-290` **Vulnerability Type**: Unsafe automatic deserialization of a predictable local cache file **Risk Level**: High ### Vulnerable Code `scripts/backtest.py:50-59`: ```python def load_kline_history(codes: List[str], days: int = 750, workers: int = 14, use_cache: bool = True) -> Dict[str, Optional[List[dict]]]: """拉取历史K线(近 days 个交易日),支持本地缓存""" cache_path = os.path.abspath(CACHE_FILE) cache: Dict[str, Optional[List[dict]]] = {} if use_cache and os.path.exists(cache_path): try: import pickle with open(cache_path, "rb") as f: cache = pickle.load(f) ``` The predictable cache location is defined at `scripts/backtest.py:42`: ```python CACHE_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "data", "kline_cache.pkl") ``` Equivalent automatic cache loading in `scripts/portfolio_backtest.py:63-67`: ```python def load_index_map() -> Dict[str, dict]: """从K线缓存构建沪深300 各周期收益映射""" with open(CACHE_FILE, "rb") as f: cache = pickle.load(f) idx_kl = cache.get("sh000300") ``` Additional equivalent loads: ```python with open(CACHE_FILE, "rb") as f: cache = pickle.load(f) ``` These occur in `rolling_nav()` at lines 230-232 and `print_nav_report()` at lines 288-290. ### Technical Analysis The Skill treats `data/kline_cache.pkl` as trusted whenever it exists. Pickle deserialization can execute attacker-controlled callables during object reconstruction, so the cache is effectively a local code-execution input rather than a passive data cache. The cache path is predictable and located inside the project tree. The code does not verify: - File ownership. - File or parent-directory permissions. - Whether the path resolve ...[truncated 1594 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the K-line pickle cache with a non-executable format such as: - Parquet. - SQLite or DuckDB. - MessagePack with strict type validation. - JSON or compressed JSON where performance permits. 2. Validate cache data against an explicit schema after parsing: - Require stock-code keys in the expected format. - Require each K-line entry to contain only the expected date and numeric fields. - Apply limits to record counts and numeric values. 3. Protect cache creation and replacement: - Create the data directory with user-only permissions. - Write to a new file using exclusive creation. - Flush and atomically rename the completed cache. - Reject symbolic links and files not owned by the current user. - Reject group-writable or world-writable cache files and parent directories. 4. If backward compatibility requires pickle temporarily, only load a cache after verifying a trusted signature or digest. A restricted unpickler alone is difficult to make safe for complex third-party objects and should not be the primary control. 5. Add tests that create permission-unsafe, symlinked, malformed, and unsigned cache files and verify rejection before deserialization. ]]>

T08 · Insecure Dependencies

Note
Location
manifest.yaml:27
Finding
Unpinned and Incompletely Declared Python Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `manifest.yaml:27-34`; related installation instructions appear in `SKILL.md:157` and `SKILL.md:203` **Vulnerability Type**: Unpinned third-party dependencies and incomplete runtime dependency declaration **Risk Level**: Low ### Vulnerable Configuration `manifest.yaml:27-34`: ```yaml dependencies: python: - requests - numpy optional: - scikit-learn - pytest ``` `SKILL.md:157` instructs installation of an additional runtime package: ```text hithink local database dependency: duckdb must be installed with pip install duckdb ``` `SKILL.md:203` provides unpinned installation instructions: ```bash pip install requests numpy ``` The documentation also identifies `scikit-learn` and `pytest` as optional packages without version constraints or integrity hashes. ### Technical Analysis The project does not pin reviewed versions, provide package hashes, or include a dependency lockfile. As a result, installation resolves whichever package versions are available through the user's configured Python package index at that time. The dynamically imported `duckdb` package is required for the preferred local database integration but is absent from the manifest's dependency lists. This creates an inconsistency between the declared runtime environment and the implementation. The observed package names correspond to established projects, and the audit found no typo-squatted package name or explicitly unsafe download URL. The risk therefore arises from non-reproducible and integrity-unverified dependency resolution rather than a confirmed malicious dependency. ### Attack Path 1. A user follows the documentation and runs an unpinned `pip install` command. 2. pip queries the user's configured package index and resolves current package versions and transitive dependencies. 3. A compromised package release, compromised index, dependency substitution, or unexpectedly incompatible release is selected. 4. ...[truncated 560 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin reviewed dependency versions or narrowly bounded compatible ranges. 2. Generate a lockfile that includes transitive dependencies and cryptographic hashes. 3. Install with hash verification, such as `pip install --require-hashes -r requirements.txt`. 4. Document and enforce an approved package index. 5. Add `duckdb` to the manifest as a runtime or clearly defined optional dependency matching the implementation. 6. Separate runtime dependencies from development and testing dependencies such as `pytest`. 7. Establish an update process that reviews dependency changes and runs the full test suite before updating pins. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (56)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
This skill claims general market scanning, but the finding indicates it also reads local positions JSON containing cost basis and share counts and produces holding-specific advice. Undeclared processing of personal portfolio files is privacy-relevant because users may invoke a stock screener without realizing it can ingest sensitive local financial data and persist or expose derived outputs.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises and documents capabilities that read local files, write outputs, access environment-derived configuration, use MCP, and make network requests, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and increases the chance the agent can be invoked with broader capabilities than users expect, especially because it handles local holdings files, local databases, and network data providers.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger list contains broad financial phrases like 量价选股, 量价形态, 板块共振, and 盘中监控 that can easily appear in ordinary conversation. Overbroad triggers can cause unintended invocation of a skill that has file, network, and MCP-related capabilities, creating unnecessary data exposure or action execution in contexts where the user did not intend to run this skill.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The trigger list contains broad, generic finance phrases such as '量价选股', '突破延续', and '盘中监控' without additional scope constraints, which can cause the skill to activate in loosely related conversations. In a finance context, unintended invocation is more sensitive because the skill may surface stock-screening output or quasi-investment guidance when the user did not explicitly request this specific system, increasing the risk of misrouting, confusion, or overbroad financial advice.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This markdown file is written entirely in Chinese and does not indicate that language selection is optional or limited to a justified region-specific context. Under the policy for natural-language violations, forcing a specific language without user opt-in is reportable.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This markdown file presents all user-facing instructions and scoring guidance exclusively in Chinese. Under the policy rule for language/locale, forcing a specific language without user opt-in is a natural-language policy violation unless the regional constraint is explicitly documented and justified, which is not present here.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
该文件标题与公式明确写明“100 分制”,且各分项相加也等于100分;而技能清单描述声称该系统使用“130分制评分(+多周期确认-5~+10)”。这不是单纯信息不全,而是文档对核心评分机制的主动表述与技能宣称不一致,容易误导使用者对实际筛选逻辑的理解。

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The report explicitly claims '无未来函数' and '无泄漏', yet the stated training window (2023-09~2025-09) overlaps the validation window beginning 2025-09-08. In a trading skill, this can materially misrepresent model validity and induce users to trust overstated backtest performance, creating a real risk of financial loss from deployment based on contaminated evaluation.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The document gives concrete '实盘建议' and executable commands for running the strategy, while presenting strong performance claims without an explicit non-advisory and loss-risk warning near those recommendations. In the context of an investment-selection skill, this increases the chance that users treat experimental backtest output as actionable financial guidance and incur losses.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This Python file contains its primary docstrings and runtime user-facing strings entirely in Chinese, including the module description and printed example output. For an all-file policy check, this is a natural-language locale choice imposed by the skill without offering a user language option or documenting a justified region-specific constraint.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This Python file contains its primary docstring usage instructions entirely in Chinese, and later user-facing CLI descriptions and runtime messages are also Chinese-only. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Content
try:
            import pickle
            with open(cache_path, "rb") as f:
                cache = pickle.load(f)
            print(f"[回测] 命中K线缓存({len(cache)}只),跳过网络拉取")
        except Exception:
            cache = {}
Confidence
97% confidence
Finding
The code deserializes a local cache file with pickle.load(), which is unsafe because pickle permits arbitrary code execution during loading. If an attacker can modify or replace the cache file in the expected path, running the backtest would execute attacker-controlled code with the privileges of the user.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The script prints warnings, status messages, table headers, and argparse help text in Chinese, which means users receive mandatory Chinese-language interaction during execution. Because no language selection or documented locale limitation is provided, this violates the language/locale policy for natural-language behavior.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The module explicitly disables system proxy settings for Tencent endpoints and hard-codes a localhost proxy for Eastmoney traffic. This can bypass enterprise egress controls, monitoring, DLP, or security inspection that rely on environment-configured proxies, and it also assumes traffic should be routed through a specific local service without validation. In a data-ingestion skill, changing network routing behavior this way is security-relevant even if done for reliability reasons.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The module docstring says watchlist mode monitors an existing命中池 and the usage example shows `python intraday.py --watchlist`. In actual code, `run_watchlist_monitor` immediately prints an error when no code list is provided, and the `--watchlist` branch only tells the user to pass stock codes manually, so the documentation contradicts the implemented behavior.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The argument help at L304 says --min-score will act as a minimum rise threshold override, and the parsed value is passed into scan_intraday at L311. However, scan_intraday never references its min_score parameter anywhere in its body, so the documented behavior is contradicted by the implementation and users cannot actually override thresholds as claimed.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code reads CODEBUDDY_MCP_CONFIG from the environment, extracts connector-proxy headers, and uses them for subsequent HTTP requests. Although the module docstring describes MCP utilities, there is no warning, comment, or user-facing logging that credentials or auth-related headers are being accessed and transmitted.

Static analysis

No suspicious patterns detected.