Back to skill

Security audit

BeerGaao 专业量化交易

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent stock-analysis tool, but it needs Review because broker credentials and unsafe local model loading create higher risk than the data-only framing suggests.

Install only in an isolated environment, use read-only and narrowly scoped API tokens, avoid Longport tokens with trading authority, protect config.env permissions, and do not load or keep model files unless you trust how they were produced. Review or update the dependency pins before using this with sensitive accounts or production workflows.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
stock_skill/models.py:21
Finding
Unsafe Joblib deserialization with bypassable path containment## Vulnerability Details **File Location**: `stock_skill/models.py:21-94` **Vulnerability Type**: Unsafe deserialization and insufficient path validation **Risk Level**: High ### Vulnerable Code ```python def _validate_model_path(file_path: str) -> None: abs_path = Path(file_path).resolve() if not str(abs_path).startswith(str(_MODELS_DIR.resolve())): raise ValueError( f"Security restriction: model files must be located under {_MODELS_DIR}." f"Attempted path: {file_path}" ) if abs_path.suffix not in _ALLOWED_EXTENSIONS: raise ValueError( f"Security restriction: extension '{abs_path.suffix}' is not allowed." ) if not abs_path.exists(): raise FileNotFoundError(f"Model file does not exist: {file_path}") ``` ```python def load_model_safe(file_path: str, loader_func=None) -> Optional[Any]: try: _validate_model_path(file_path) if not _check_file_integrity(file_path): logger.error(f"Model integrity check failed: {file_path}") return None if loader_func is None: import joblib loader_func = joblib.load model = loader_func(file_path) return model except Exception as e: logger.error(f"Model loading failed: {e}") return None ``` ### Technical Analysis `joblib.load()` uses Python pickle-compatible deserialization. Pickle data may contain reduction instructions that import modules and invoke arbitrary callables during deserialization. Loading a malicious Joblib file therefore amounts to executing code with the privileges of the running process. The `_check_file_integrity()` routine does not establish authenticity or integrity. It only limits file size and checks the filename for selected substrings. It does not compare a cryptographic digest, validate a digital signature, inspect ownership, ...[truncated 2014 chars]
Remediation
## Remediation Suggestions 1. Replace the string-prefix check with a component-aware containment check: ```python trusted_root = _MODELS_DIR.resolve(strict=True) candidate = Path(file_path).resolve(strict=True) if not candidate.is_relative_to(trusted_root): raise ValueError("Model path is outside the trusted model directory") ``` 2. Verify that the candidate is a regular file and reject symbolic links or other special files where appropriate: ```python if candidate.is_symlink() or not candidate.is_file(): raise ValueError("Model must be a regular, non-symlink file") ``` 3. Avoid pickle and Joblib for files that are not guaranteed to be trusted. Prefer non-executable formats such as safetensors or a strictly validated JSON representation. 4. If Joblib must remain supported, require a cryptographic signature or an allowlisted SHA-256 digest generated through a trusted model-build process. 5. Store trusted models in a directory that is not writable by untrusted users or unrelated application components. 6. Remove `.pkl` and `.joblib` from the allowed extension list when executable serialization is unnecessary. 7. Add tests covering sibling-prefix paths, symbolic links, replaced model files, and malformed serialized content.

T09 · Insecure Skill Coding Practices

Warning
Location
stock_skill/strategies/ml_strategies.py:224
Finding
Public model persistence method permits writes to arbitrary filesystem directories## Vulnerability Details **File Location**: `stock_skill/strategies/ml_strategies.py:224-250` **Vulnerability Type**: Unrestricted filesystem path and arbitrary file overwrite **Risk Level**: Medium ### Vulnerable Code ```python def save_model(self, path: str = None) -> str: if not self.is_trained or self.model is None: return "" save_dir = Path(path) if path else _MODEL_DIR / self.name save_dir.mkdir(parents=True, exist_ok=True) try: import joblib except ImportError: return "" model_path = save_dir / "model.joblib" joblib.dump(self.model, model_path) meta = { "feature_columns": self.feature_columns, "train_samples": self._train_samples, "train_history": self._train_history, "feature_importance": dict(sorted( self.feature_importance.items(), key=lambda x: x[1], reverse=True )[:20]), } with open(save_dir / "meta.json", "w", encoding="utf-8") as f: json.dump(meta, f, ensure_ascii=False, indent=2) return str(save_dir) ``` ### Technical Analysis The public `save_model()` method accepts an arbitrary `path` and uses it directly as the destination directory. It creates the directory recursively and overwrites `model.joblib` and `meta.json` without checking whether the destination is inside the documented model directory. There are no checks for path containment, symbolic links, destination ownership, existing files, or safe file permissions. Although the standard Agent tool definitions reviewed during the audit do not directly expose this path parameter, any extension, integration, plugin, or direct Python caller that passes untrusted input into this public method can turn it into a filesystem write primitive. Because `open(..., "w")` and `joblib.dump()` truncate existing destination files, pre-existing files with the expected names may be overwritten. ### Attack Pat ...[truncated 1027 chars]
Remediation
## Remediation Suggestions 1. Remove the caller-controlled path unless it is operationally necessary. 2. Resolve the requested directory and enforce component-aware containment beneath `_MODEL_DIR` with `Path.is_relative_to()`. 3. Reject symbolic links in every destination path component. 4. Create files using restrictive permissions and atomic replacement through a temporary file in the same trusted directory. 5. Refuse to overwrite an existing model unless the caller explicitly requests replacement through a trusted internal API. 6. Expose logical model identifiers rather than raw filesystem paths. 7. Add tests for absolute paths, `..` traversal, sibling-prefix directories, and symlink destinations.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
stock_skill/providers/providers.py:275
Finding
Quote-only Longport provider unnecessarily initializes a privileged trading context## Vulnerability Details **File Location**: `stock_skill/providers/providers.py:275-307` **Vulnerability Type**: Excessive broker capability and violation of least privilege **Risk Level**: Medium ### Vulnerable Code ```python class LongportProvider: def __init__(self): cfg = get_config() self._config = cfg self._quote_ctx = None self._trade_ctx = None self._initialized = False def _init_context(self): if self._initialized: return if not all([ self._config.longport_app_key, self._config.longport_app_secret, self._config.longport_access_token ]): return from longport.openapi import Config, QuoteContext, TradeContext lp_config = { "app_key": self._config.longport_app_key, "app_secret": self._config.longport_app_secret, "access_token": self._config.longport_access_token, } config = Config(**lp_config) self._quote_ctx = QuoteContext(config) self._trade_ctx = TradeContext(config) self._initialized = True ``` ### Technical Analysis The provider documentation states that Longport is used only for market-data queries and does not execute trades. Nevertheless, `_init_context()` imports and creates a `TradeContext` using the configured broker credentials. No real order-submission call was found in the audited provider, and the execution module contains only an abstract broker interface and a simulated broker implementation. However, creating and retaining an authenticated trading context grants the process access to functionality beyond what is required for quote retrieval. This expands the consequences of a process compromise, dependency compromise, accidental future invocation, or malicious extension. It also conflicts with the documented recommendation to use read-only ...[truncated 993 chars]
Remediation
## Remediation Suggestions 1. Remove `TradeContext` from the quote provider: ```python from longport.openapi import Config, QuoteContext self._quote_ctx = QuoteContext(config) ``` 2. Do not retain a `_trade_ctx` attribute in a data-only component. 3. Require credentials or scopes that are technically incapable of order submission. 4. Separate any future trading implementation into an independent, disabled-by-default component with explicit user confirmation and authorization. 5. Add a regression test asserting that market-data operations never instantiate or call trading APIs. 6. Document the exact Longport scopes required and reject credentials with excessive permissions when the API permits scope inspection.

T09 · Insecure Skill Coding Practices

Warning
Location
stock_skill/config.py:8
Finding
Plaintext credential file is loaded without permission validation## Vulnerability Details **File Location**: `stock_skill/config.py:8-13`; related instructions in `SKILL.md:70-100` **Vulnerability Type**: Insecure local credential storage **Risk Level**: Medium ### Vulnerable Code ```python try: from dotenv import load_dotenv _env_path = Path(__file__).parent.parent / "config.env" if _env_path.exists(): load_dotenv(_env_path) else: load_dotenv() except ImportError: pass ``` The installation instructions direct users to create the file: ```bash cp config.example.env config.env # Edit config.env and add API credentials ``` ### Technical Analysis The Skill instructs users to store Tushare and Longport credentials in a plaintext `config.env` file. The loader reads this file without checking its owner, type, symbolic-link status, or permission mode. The source tree applies restrictive permissions to its SQLite database, but it does not apply equivalent protection to the more sensitive credential file. Consequently, the effective file mode depends on the user's umask and how the file was copied or created. The Skill documentation also claims that `config.env` is excluded through `.gitignore`, but no `.gitignore` appeared in the audited project structure. This increases the risk of accidental source-control inclusion. ### Attack Path 1. A user follows the documented setup and copies `config.example.env` to `config.env`. 2. The resulting file inherits permissions affected by the local umask and may be readable by other local users or service accounts. 3. The user adds API keys or broker access tokens to the plaintext file. 4. Another local principal reads the file, or the file is accidentally added to version control because the audited project does not contain the claimed ignore rule. 5. The exposed credentials are reused against their corresponding external services. ### Impact Assessment Exposure may compromise Tushare d ...[truncated 420 chars]
Remediation
## Remediation Suggestions 1. Prefer an operating-system secret store, container secret mount, or dedicated secret manager over a project-local plaintext file. 2. If `config.env` remains supported, verify that it is a regular, non-symlink file owned by the expected user. 3. Reject or warn on group-readable or world-readable modes, and require mode `0600` on POSIX systems. 4. Add a repository `.gitignore` containing at least: ```text config.env .env .data/ stock_skill.log models/ ``` 5. Add automated secret scanning to continuous integration and pre-commit workflows. 6. Update setup instructions to create the file securely, for example with a restrictive umask. 7. Continue recommending read-only, narrowly scoped credentials and rotate any credentials that may already have been committed or exposed.

T08 · Insecure Dependencies

Note
Location
requirements.txt:10
Finding
Unbounded AkShare dependency permits installation of unreviewed future releases## Vulnerability Details **File Location**: `requirements.txt:10`; duplicated in `pyproject.toml:38` **Vulnerability Type**: Non-reproducible dependency resolution and supply-chain exposure **Risk Level**: Low ### Vulnerable Code ```text akshare>=1.10.0 ``` ### Technical Analysis The minimum-only version constraint allows package installation tools to select any later AkShare release available at installation time. The effective dependency code can therefore change after the Skill itself has been reviewed. No evidence was found that AkShare is currently malicious. The risk comes from dependency drift: a compromised upstream account, malicious future release, or incompatible update could introduce unreviewed behavior into new installations. Unlike exact pins, the current specification does not provide reproducible resolution. Exact versions used elsewhere in the dependency list reduce this risk, but no hash-locked dependency file was identified. ### Attack Path 1. A future AkShare release is compromised or publishes malicious installation or import-time behavior. 2. A user installs the Skill after that release becomes the newest version satisfying the minimum constraint. 3. The package manager resolves and installs the compromised release. 4. Malicious package code executes during installation, import, or normal provider use with the user's privileges. ### Impact Assessment A compromised dependency can generally execute with the privileges of the Python installation or Skill process. Potential impact includes reading environment credentials, altering project files, accessing local state, and making unauthorized network requests. This is a potential supply-chain path rather than evidence of an active malicious dependency in the audited artifact.
Remediation
## Remediation Suggestions 1. Pin AkShare to a specifically reviewed version in both `requirements.txt` and `pyproject.toml`. 2. Generate a lockfile containing cryptographic hashes for all direct and transitive dependencies. 3. Install with hash verification in deployment and continuous-integration environments. 4. Use automated dependency monitoring, but review and test updates before changing the lockfile. 5. Build and install dependencies from a controlled package index or approved artifact repository where practical.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (81)

Known Vulnerable Dependency: lightgbm==4.0.0 — 2 advisory(ies): CVE-2024-43598 (LightGBM Remote Code Execution Vulnerability); CVE-2024-43598 (LightGBM Remote Code Execution Vulnerability)

Critical
Category
Supply Chain
Confidence
90% confidence
Finding
The optional ml dependency pins lightgbm==4.0.0, which is flagged for a critical RCE advisory. Even though it is optional, this package materially increases risk in environments using ML features, especially if models, datasets, or configuration inputs can come from external or user-controlled sources.

Credential Access

High
Category
Privilege Escalation
Content
pip install -e ".[tushare]"

# 配置环境变量
cp .env.example .env
# 编辑 .env 填入配置(TUSHARE_TOKEN 为可选,仅 Tushare 数据源需要)

# 运行主程序
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 配置环境变量
cp .env.example .env
# 编辑 .env 填入配置(TUSHARE_TOKEN 为可选,仅 Tushare 数据源需要)

# 运行主程序
python -m stock_skill                    # 完整复盘
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Continuous position monitoring, stop-loss/take-profit alerting, and circuit-breaker monitoring go beyond a simple on-demand analysis skill and introduce autonomous or semi-persistent operational behavior not clearly declared in the purpose. Hidden monitoring/callback behavior is riskier because it may trigger network activity, polling, or alert workflows without clear user expectation or consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
Continuous position monitoring, stop-loss/take-profit alerting, and circuit-breaker monitoring go beyond a simple on-demand analysis skill and introduce autonomous or semi-persistent operational behavior not clearly declared in the purpose. Hidden monitoring/callback behavior is riskier because it may trigger network activity, polling, or alert workflows without clear user expectation or consent.

Credential Access

High
Category
Privilege Escalation
Content
| `TUSHARE_TOKEN` | Tushare API token(只读) | 是 |
| `LONGPORT_APP_KEY` | 长桥 App Key | 否 |
| `LONGPORT_APP_SECRET` | 长桥 App Secret | 否 |
| `LONGPORT_ACCESS_TOKEN` | 长桥 Access Token(建议只读) | 否 |

## 安全说明
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| `TUSHARE_TOKEN` | Tushare API token(只读) | 是 |
| `LONGPORT_APP_KEY` | 长桥 App Key | 否 |
| `LONGPORT_APP_SECRET` | 长桥 App Secret | 否 |
| `LONGPORT_ACCESS_TOKEN` | 长桥 Access Token(建议只读) | 否 |

## 安全说明
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Known Vulnerable Dependency: pytest==7.4.0 — 2 advisory(ies): CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)

High
Category
Supply Chain
Confidence
80% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The file title and all operational guidance are presented as a Chinese-only project规范, which effectively imposes a specific language for skill interaction/documentation. The policy allows locale constraints only when justified or when users are given a language choice, neither of which is stated here.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The documentation states the natural-language capability as supporting Chinese interaction and gives only a Chinese example, which imposes a locale expectation without any opt-in or alternative language guidance. Under the policy, language constraints should either be optional or clearly justified as region-specific.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The README makes a security-relevant claim that the tool only reads public market data and does not perform actual trading, yet other documented capabilities include Longbridge/OpenAPI credentials and a position-query feature that imply access to brokerage-linked or account-scoped data. This kind of misleading assurance can cause users to grant higher-privilege credentials or deploy the tool in more trusted environments under a false assumption about its access scope.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill advertises access to environment variables and the implementation apparently uses filesystem, network, and shell-capable behaviors, but the manifest does not declare any explicit tool scope such as permissions or allowed-tools. That creates an over-privileged, under-specified trust boundary where a host agent may grant broader capabilities than users expect, increasing the risk of unintended file, shell, or network actions.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The example trigger "复盘一下" is very generic everyday language and is mapped directly to `full_review()` without any scope constraints or exclusion conditions. In a markdown skill description, this kind of broad trigger can cause unintended activation because it does not specify what context or asset set should be reviewed.

Known Vulnerable Dependency: requests==2.31.0 — 6 advisory(ies): CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi); CVE-2026-25645 (Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility func) +3 more

Medium
Category
Supply Chain
Confidence
92% confidence
Finding
The project pins requests==2.31.0, a version with multiple published advisories. In a quant/trading tool that likely makes outbound HTTP requests to market-data providers and APIs, dependency flaws can expose credentials, weaken TLS/session validation, or otherwise compromise request handling in real deployments.

Known Vulnerable Dependency: python-dotenv==1.0.0 — 2 advisory(ies): CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)

Medium
Category
Supply Chain
Confidence
79% confidence
Finding
The project pins python-dotenv==1.0.0, which is reported with file-handling issues such as symlink following during key updates. This becomes relevant if the tool writes or modifies .env files in environments where attackers can influence paths or filesystem layout, potentially leading to arbitrary file overwrite.

Known Vulnerable Dependency: scikit-learn==1.3.0 — 2 advisory(ies): CVE-2024-5206 (scikit-learn sensitive data leakage vulnerability); CVE-2024-5206 (A sensitive data leakage vulnerability was identified in scikit-learn's TfidfVec)

Medium
Category
Supply Chain
Confidence
72% confidence
Finding
The dependency scikit-learn==1.3.0 is flagged for sensitive data leakage issues. In a financial-analysis skill, models may process proprietary trading features or user-supplied datasets, so leakage from vectorization or model-processing components could expose confidential inputs under affected usage patterns.

Known Vulnerable Dependency: requests==2.31.0 — 6 advisory(ies): CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi); CVE-2026-25645 (Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility func) +3 more

Medium
Category
Supply Chain
Confidence
97% confidence
Finding
requests==2.31.0 has published advisories affecting request handling, including credential leakage and session verification flaws under certain usage patterns. This skill is a quant analysis tool and likely performs network access to fetch market data, so a vulnerable HTTP client is materially relevant and could expose credentials, weaken transport security, or mishandle untrusted URLs if the surrounding code uses affected features.

Known Vulnerable Dependency: python-dotenv==1.0.0 — 2 advisory(ies): CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)

Medium
Category
Supply Chain
Confidence
84% confidence
Finding
python-dotenv==1.0.0 is flagged for a file-handling issue involving symlink following during key updates, which can lead to arbitrary file overwrite in workflows that modify .env files. The risk is lower in this requirements file alone because exploitation depends on the application actually calling affected write paths, but if the skill includes environment-management features or setup scripts, the vulnerable version remains an unnecessary exposure.

Known Vulnerable Dependency: scikit-learn==1.3.0 — 2 advisory(ies): CVE-2024-5206 (scikit-learn sensitive data leakage vulnerability); CVE-2024-5206 (A sensitive data leakage vulnerability was identified in scikit-learn's TfidfVec)

Medium
Category
Supply Chain
Confidence
86% confidence
Finding
scikit-learn==1.3.0 is associated with a sensitive data leakage issue in specific vectorization-related functionality. In the context of a stock quant tool, this is less directly exposed unless the skill processes sensitive text corpora or user-provided data through affected components, but keeping a known-vulnerable ML library still creates avoidable risk and may become relevant if the skill expands its feature set.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This Python file contains user-facing natural-language text entirely in Chinese, beginning with the module docstring "专业回测引擎". The file does not offer any language/locale option or explain that it is intentionally restricted to a China-specific or Chinese-language context, which can violate the policy against forcing a specific language without user opt-in.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The file's natural-language documentation string is written only in Chinese, and validation/error messages later in the file are also Chinese-only. That indicates a language choice is being imposed without any visible opt-in or justification for a locale-specific restriction in this file.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The docstrings and validation messages such as '未配置' are Chinese-only natural-language outputs. There is no indication here that users can choose their language or that the skill is explicitly limited to a Chinese-speaking context.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code path performs safety-critical state-changing operations by submitting buy/sell orders, modifying cash and positions, and recording fills, but it contains no confirmation prompt, print/log disclosure, or explicit warning comment/docstring about the impact of executing trades. For an execution-layer skill, trading may be part of the purpose, but the file itself provides no user disclosure around the irreversible financial effects of order execution.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file’s human-readable descriptions, docstrings, and log messages are entirely in Chinese, with no indication that the skill is region-specific or that users can opt into this locale. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation.

External Transmission

Medium
Category
Data Exfiltration
Content
_EASTMONEY_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Referer": "https://data.eastmoney.com/",
}
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.