Back to skill

Security audit

小果量化交易Ptrade全能助手

Security checks for vulnerabilities and agentic risk

Overview

This Ptrade skill contains broad live trading, account-operation, margin/futures, and persistent state code with unclear scoping that users should review carefully before installing.

Review this as live brokerage automation, not just educational strategy notes. Do not install or copy the bundled templates into Ptrade unless you separate the examples, remove or gate fund-transfer, margin, futures, IPO, and reverse-repo actions, replace pickle state with safe serialization, and test only in a sandbox/backtest account with explicit order confirmations.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
assets/strategy_template.py:4978
Finding
Arbitrary Code Execution Through Unsafe Pickle Deserialization<![CDATA[ ## Vulnerability Details **File Location**: `assets/strategy_template.py:4978-5059` **Vulnerability Type**: Unsafe deserialization of mutable local files **Risk Level**: High ### Vulnerable Code ```python import pickle NOTEBOOK_PATH='' def initialize(context): NOTEBOOK_PATH = get_research_path()#+'xsz/'#'/home/fly/notebook/' # Persistence: attempt to initialize pickle files if not is_trade(): with open(NOTEBOOK_PATH+'count.pkl','wb') as f: pickle.dump(1,f,-1) with open(NOTEBOOK_PATH+'firstcount.pkl','wb') as f: pickle.dump(0,f,-1) try: with open(NOTEBOOK_PATH+'count.pkl','rb') as f: g.count = pickle.load(f) log.info("Strategy restart initialization, current strategy trading day read from file: %s" % (g.count)) with open(NOTEBOOK_PATH+'firstcount.pkl','rb') as f: g.trade_count = pickle.load(f) log.info("Strategy restart initialization, strategy has run for %s trading days" % (g.trade_count)) except Exception as e: log.error("Failed to read count and firstcount files: %s" % (e)) ``` ### Technical Analysis Python pickle is not a data-only serialization format. During `pickle.load()`, specially constructed objects can invoke attacker-selected Python callables through reduction opcodes. Consequently, loading a pickle file is equivalent to executing code supplied by whoever controls that file. The strategy loads `count.pkl` and `firstcount.pkl` from the path returned by `get_research_path()` without validating file ownership, permissions, provenance, integrity, or expected structure. Although backtest mode overwrites these files before loading them, live trading mode does not necessarily do so. A pre-existing or replaced file can therefore reach `pickle.load()` directly. The exception handler does not mitigate the vulnerability because payload execution occurs during deserialization, before a malicious object must retur ...[truncated 1413 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all uses of `pickle.load()` for persistent counters or other externally mutable state. 2. Store primitive values in a data-only format such as JSON: ```python import json with open(counter_path, "r", encoding="utf-8") as f: value = json.load(f) if not isinstance(value, int) or value < 0: raise ValueError("Invalid counter value") ``` 3. Use a dedicated private state directory rather than a broadly shared research directory. 4. Restrict directory and file permissions to the account running the strategy. 5. Write updates atomically by creating a temporary file in the same directory and replacing the destination only after a successful flush. 6. If state authenticity matters, verify it with a keyed MAC whose key is stored outside the writable state directory. 7. Validate every loaded field against an explicit schema, including type and acceptable numeric range. 8. Document the state files and fail safely if their ownership or permissions are unexpected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
assets/strategy_template.py:27
Finding
Concatenated Template Silently Activates a Leveraged Futures Strategy<![CDATA[ ## Vulnerability Details **File Location**: `assets/strategy_template.py:27-7253` **Vulnerability Type**: Duplicate lifecycle definitions causing unintended high-impact trading behavior **Risk Level**: High ### Vulnerable Code The advertised template contains many repeated definitions of the same Ptrade lifecycle functions. The final definitions in the file replace all earlier definitions under normal Python name-binding rules: ```python """ Strategy name: Futures dual-moving-average strategy Execution period: Daily ============================================================================== Note: This demo only supports backtesting. For trading, the dominant contract, such as "IF888.CCFX", must be replaced with a currently listed contract. """ import numpy as np def initialize(context): g.target = 'IF' g.security = g.target + '888.CCFX' g.amount = 1 if not is_trade(): set_limit_mode('UNLIMITED') set_margin_rate(g.target, 0.15) def before_trading_start(context, data): h = get_history( 20, '1d', field=['close', 'volume'], security_list=g.security, fq='dypre', include=False, is_dict=True ) g.close_data = h[g.security]['close'] def handle_data(context, data): current_price = data[g.security].close close_data = np.concatenate( (g.close_data, np.array(list([current_price]))), axis=0 ) ma5 = get_ma(close_data, 5) ma10 = get_ma(close_data, 10) if ma5 > ma10: if get_position(g.security).long_amount == 0: order_id = buy_open(g.security, g.amount) log.info("Open long position %s" % g.security) if get_position(g.security).short_amount != 0: order_id = buy_close(g.security, g.amount) log.info("Close short position %s" % g.security) elif ma5 < ma10: if get_position(g.security).short_amount == 0: order_id = sell_open(g.security, ...[truncated 3309 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Split each example strategy into a separate Python file. Stock, margin, ETF, and futures examples must not share one executable module. 2. Ensure each executable strategy file contains exactly one `initialize()` and one `handle_data()` definition. 3. Add a static validation step that rejects duplicate Ptrade lifecycle functions, including: - `initialize` - `handle_data` - `before_trading_start` - `after_trading_end` - `tick_data` 4. Make the documented `STRATEGY_CONFIG` the sole source of configurable behavior in the corresponding template. 5. Place futures strategies under clearly named files such as `futures_dual_ma_strategy.py`, with prominent derivatives and leverage warnings. 6. Require explicit user confirmation before enabling live futures, margin, fund-transfer, or other high-impact account APIs. 7. Add a dry-run mode that logs intended orders without submitting them. 8. At startup, log the selected asset class, exact instrument, account mode, order APIs, and maximum exposure, then abort if these conflict with the declared configuration. 9. Update `references/strategy_notes.md` so users copy only a specific, validated strategy file rather than a concatenated collection of examples. ]]>
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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (35)

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The document includes fund-transfer capabilities, which go beyond strategy assistance into direct asset movement. In a brokerage context this is especially dangerous because misuse or accidental adoption could move cash between venues/accounts and amplify loss, fraud, or operational damage beyond a single trade.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding correctly identifies that the actual content does not implement many of the claimed assistant features while instead providing executable strategy material. The main risk is misleading scope and user overtrust rather than direct code exploitation, but in a financial automation context that still has meaningful safety impact.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding correctly identifies that the actual content does not implement many of the claimed assistant features while instead providing executable strategy material. The main risk is misleading scope and user overtrust rather than direct code exploitation, but in a financial automation context that still has meaningful safety impact.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
This finding correctly identifies that the actual content does not implement many of the claimed assistant features while instead providing executable strategy material. The main risk is misleading scope and user overtrust rather than direct code exploitation, but in a financial automation context that still has meaningful safety impact.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
This finding correctly identifies that the actual content does not implement many of the claimed assistant features while instead providing executable strategy material. The main risk is misleading scope and user overtrust rather than direct code exploitation, but in a financial automation context that still has meaningful safety impact.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
This finding correctly identifies that the actual content does not implement many of the claimed assistant features while instead providing executable strategy material. The main risk is misleading scope and user overtrust rather than direct code exploitation, but in a financial automation context that still has meaningful safety impact.

Missing User Warnings

High
Confidence
95% confidence
Finding
The skill promotes live trading automation and practical execution guidance without an explicit warning about real-money consequences. In the context of automated brokerage operations, omission of such warnings materially increases the likelihood of unsafe use, overtrust, and accidental financial harm.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The skill presents itself as a strategy assistant, but these sections expose concrete trading APIs and workflows that can be used to place real orders. In the context of retail or brokerage automation, this is dangerous because it lowers the barrier to executing financially impactful actions under the guise of 'assistance' documentation.

Context-Inappropriate Capability

High
Confidence
93% confidence
Finding
Bulk IPO subscription capability is not inherently malicious, but it materially expands the operational scope of the skill beyond analysis/support. That mismatch is risky because users may trigger or rely on instructions for capital deployment actions they did not expect the skill to facilitate.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The reverse-repurchase strategy and account/order/position query helpers directly interact with available cash, orders, and holdings. In a real brokerage setting, this is dangerous because it extends the skill from passive assistance into active cash deployment and sensitive account-state handling without matching scope declarations.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The file is described as a strategy template/helper, but actually contains a large catalog of directly executable strategies with order placement logic across equities, ETFs, futures, margin, and reverse repo. That mismatch expands the operational attack surface and creates a dangerous capability gap where users may invoke live trading behavior they did not reasonably expect from a helper skill.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The inclusion of margin trading, futures trading, and reverse repurchase logic goes beyond the stated quant-assistant purpose and materially increases risk. These features can create leveraged or non-cash exposures, so misuse or compromise would have amplified financial impact compared with ordinary strategy analysis tooling.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger list includes generic finance phrases such as “双均线策略”, “金叉死叉”, “量化回测”, “金叉买入”, and “死叉卖出” without contextual limits. These are common terms in normal discussion of trading strategies, so the skill could activate unintentionally when a user is merely talking about markets rather than invoking this specific skill.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
L04318 的注释写明“使用80%的可用资金买入”,但下一行实际赋值为 buy_value = cash * 1.0,并将全部可用现金用于买入。这里不是简单遗漏,而是注释对资金使用比例作出了与代码相反的明确表述。

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
技能描述强调策略辅助、生成、分析和指导,但这里会在研究路径下读写 pickle 文件保存计数状态;同文件注释中还包含维护本地财报 CSV 的实现路径。对一个以策略辅助和分析为主的技能而言,本地持久化并不是显式声明的能力,也不是该目的的明显必需项。

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This code writes and later reads persistent state files (`count.pkl` and `firstcount.pkl`) under the research path, which modifies local filesystem state across runs. Although the code comments describe the mechanics, there is no user-facing confirmation, warning, or disclosure that the skill will create and maintain local files.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Content
pickle.dump(0,f,-1)
    try:# 从文件中读取count和firstcount的值
        with open(NOTEBOOK_PATH+'count.pkl','rb') as f:
            g.count = pickle.load(f)
            log.info("策略重启初始化,从文件中读取本策略当前交易日: %s" % (g.count)) 
        with open(NOTEBOOK_PATH+'firstcount.pkl','rb') as f:
            g.trade_count = pickle.load(f)
Confidence
98% confidence
Finding
The code uses pickle.load() on files under NOTEBOOK_PATH without any integrity check, type restriction, or trust boundary enforcement. In Python, pickle deserialization can execute attacker-controlled code during loading, so if an attacker can replace or tamper with count.pkl they can achieve arbitrary code execution in the strategy process.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Content
g.count = pickle.load(f)
            log.info("策略重启初始化,从文件中读取本策略当前交易日: %s" % (g.count)) 
        with open(NOTEBOOK_PATH+'firstcount.pkl','rb') as f:
            g.trade_count = pickle.load(f)
            log.info("策略重启初始化,从文件中读取本策略运行第%s个交易日" % (g.trade_count)) 
    except Exception as e:
        log.error("读取count和firstcount文件失败: %s" % (e))
Confidence
98% confidence
Finding
This second pickle.load() reads firstcount.pkl from local storage and has the same unsafe deserialization property. Because this skill runs in a trading automation context, successful exploitation could let an attacker run arbitrary code and then place unauthorized orders, alter strategy state, or exfiltrate account information.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
`record_counters` overwrites local pickle files on disk during routine execution, which is a file write operation with persistent side effects. The implementation lacks a user-facing warning or explicit disclosure near the operation that strategy state is being saved locally.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This block creates and updates a local `finance_data.csv` cache, potentially storing sizable historical financial data on disk. While the comments explain the purpose, there is no clear user-facing disclosure that the skill will create and maintain local cache files.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
L6013 明确写明“改买入委托方式为限价单”,给人以该段实现已切换为限价委托的理解。然而实际买入实现 `open_position` 在 L6799 直接调用 `order_value(stock, vol)`,并未传入限价参数,也未使用对应限价接口,和注释表达的交易意图相矛盾。

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This duplicated strategy section again initializes and reads local pickle state files, creating persistent filesystem side effects. The code lacks a clear warning to users that running the strategy will read/write local state files across sessions.

Static analysis

No suspicious patterns detected.