Back to skill

Security audit

XTrade Futu Paper Trade

Security checks for vulnerabilities and agentic risk

Overview

This paper-trading skill is mostly coherent, but it needs Review because it can install mutable packages, submit a trading password to a configurable host, and place or cancel simulated orders without confirmation.

Install only if you are comfortable with a skill that can mutate its Python environment, contact FutuOpenD and AkShare-backed providers, and perform paper-trading order changes. Keep FUTU_HOST on a trusted local FutuOpenD endpoint, avoid using a reusable account password as FUTU_PASSWORD, do not run automated trading loops unattended, and prefer pinned dependencies or a prebuilt environment before use.

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

T08 · Insecure Dependencies

Error
Location
xtrade_futu_skill.py:56
Finding
Automatic Installation of Unpinned Third-Party Dependencies## Vulnerability Details **File Location**: `xtrade_futu_skill.py:56-81`, `requirements.txt:1-2` **Vulnerability Type**: Supply-chain exposure through automatic installation of mutable dependency versions **Risk Level**: High **Vulnerable code (`xtrade_futu_skill.py:56-81`):** ```python def ensure_venv(): if os.environ.get("FUTU_SKILL_VENV") == "1": return base_dir = Path(__file__).resolve().parent venv_dir = base_dir / ".venv" python_path = venv_dir / "bin" / "python" pip_path = venv_dir / "bin" / "pip" if sys.platform.startswith("win"): python_path = venv_dir / "Scripts" / "python.exe" pip_path = venv_dir / "Scripts" / "pip.exe" python_cmd = select_python() if python_path.exists(): venv_version = get_python_version(str(python_path)) if not is_compatible_python(venv_version): shutil.rmtree(venv_dir, ignore_errors=True) if not python_path.exists(): subprocess.check_call([python_cmd, "-m", "venv", str(venv_dir)]) if not pip_path.exists(): raise RuntimeError("虚拟环境创建失败") requirements = base_dir / "requirements.txt" subprocess.check_call([str(pip_path), "install", "-r", str(requirements)]) env = os.environ.copy() env["FUTU_SKILL_VENV"] = "1" subprocess.check_call([str(python_path), str(Path(__file__).resolve()), *sys.argv[1:]], env=env) sys.exit(0) ``` **Mutable dependency declarations (`requirements.txt:1-2`):** ```text futu-api>=1.0.0 akshare>=1.18.0 ``` ### Technical Analysis The Skill automatically invokes `pip install` whenever it starts outside the managed virtual environment. Both dependencies use lower-bound constraints rather than exact, reviewed versions. No lockfile, package hashes, or trusted-index enforcement is present. Consequently, the effective code executed by the Skill can change without any modification to the audited repository. A new ...[truncated 1709 chars]
Remediation
## Remediation Suggestions 1. Pin every direct and transitive dependency to an exact, reviewed version. 2. Generate a reproducible lockfile containing cryptographic hashes for all supported platforms. 3. Install with hash verification, such as `pip install --require-hashes -r requirements.lock`. 4. Configure an explicitly trusted package index instead of silently accepting the user's ambient pip index configuration. 5. Do not run dependency installation on every invocation. Separate installation from normal Skill execution and require explicit user approval before downloading packages. 6. Record and verify the expected dependency manifest before launching the installed interpreter. 7. Add automated dependency vulnerability scanning and controlled update review to the release process. 8. Execute the Skill under a minimally privileged account with a restricted environment so a dependency compromise cannot access unrelated secrets.

T09 · Insecure Skill Coding Practices

Error
Location
xtrade_futu_skill.py:976
Finding
Trading Password Can Be Sent to an Arbitrary Environment-Configured Host## Vulnerability Details **File Location**: `xtrade_futu_skill.py:151-155`, `xtrade_futu_skill.py:976-990`, `xtrade_futu_skill.py:993-1006` **Vulnerability Type**: Unvalidated remote endpoint used for sensitive credential submission **Risk Level**: High **Endpoint construction (`xtrade_futu_skill.py:151-155`):** ```python def open_contexts(host, port, trd_market): OpenQuoteContext, create_trade_context, _, _, _, _, _, _ = load_futu() quote_ctx = OpenQuoteContext(host=host, port=port) trade_ctx = create_trade_context(host, port, trd_market) return quote_ctx, trade_ctx ``` **Credential retrieval and submission (`xtrade_futu_skill.py:976-990`):** ```python def unlock_trade(trade_ctx): _, _, _, _, _, _, _, _ = load_futu() password = get_env("FUTU_TRADE_PWD", get_env("FUTU_PASSWORD", "")) if not password: json_out({"ok": False, "error": "缺少 FUTU_TRADE_PWD"}, 1) handler = find_trade_handler(trade_ctx, ("unlock_trade",)) if handler is None: json_out({"ok": False, "error": "当前 futu-api 未提供交易解锁接口"}, 1) result = call_ctx_method( handler, [(["password", "pwd", "unlock_password"], password)], [password], ) ret, data = result if ret != 0: json_out({"ok": False, "error": str(data)}, 1) ``` **User-configurable host used before unlocking (`xtrade_futu_skill.py:993-1006`):** ```python def cmd_order(args, side): host = get_env("FUTU_HOST", "127.0.0.1") port = int(get_env("FUTU_PORT", "11111")) trd_env = parse_trd_env(get_env("FUTU_TRD_ENV", "SIMULATE")) trd_market = parse_trd_market(get_env("FUTU_TRD_MARKET", "HK")) symbol = args.symbol price = float(args.price) qty = int(args.qty) order_type = args.order_type.lower() _, _, _, _, TrdSide, OrderType, _, _ = load_futu() quote_ctx, trade_ctx = open_contexts(host, port, trd_market) try: unlock ...[truncated 2544 chars]
Remediation
## Remediation Suggestions 1. Enforce loopback destinations (`127.0.0.1`, `::1`, or a securely resolved equivalent) by default for all operations that submit credentials. 2. Reject non-loopback `FUTU_HOST` values unless a separate explicit option such as `FUTU_ALLOW_REMOTE_HOST=1` is enabled. 3. For remote operation, require an administrator-defined hostname allowlist and authenticated, encrypted transport with certificate or endpoint identity verification. 4. Display or log the selected destination without exposing the password, and require explicit confirmation before the first credential-bearing connection to a remote endpoint. 5. Remove the fallback from `FUTU_TRADE_PWD` to `FUTU_PASSWORD` so a general account password is not inadvertently used as the trading unlock secret. 6. Keep the secret in process memory only for the shortest necessary period and ensure exceptions and debug output never serialize it. 7. Document the trust boundary around `FUTU_HOST`, including the risk of environment-variable manipulation by wrappers, schedulers, and agent runtimes. 8. Add tests confirming that `buy`, `sell`, and `cancel` reject unapproved remote hosts before reading or submitting the credential.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The manifest describes a limited paper-trading skill, but the documented behavior is substantially broader: it installs dependencies, manages orders, queries fills/funds/PnL, fetches historical market data, and pulls third-party financial data via AkShare. This mismatch is dangerous because reviewers and users may trust a narrower capability set than the skill actually exercises, leading to under-scoped approval and unexpected data access or account-impacting actions.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
raise RuntimeError("虚拟环境创建失败")
    requirements = base_dir / "requirements.txt"
    subprocess.check_call([str(pip_path), "install", "-r", str(requirements)])
    env = os.environ.copy()
    env["FUTU_SKILL_VENV"] = "1"
    subprocess.check_call([str(python_path), str(Path(__file__).resolve()), *sys.argv[1:]], env=env)
    sys.exit(0)
Confidence
96% confidence
Finding
The skill copies the full ambient environment and passes it into a child Python process. In agent and CI-like runtimes, environment variables often contain API keys, tokens, and other secrets; forwarding them wholesale to a subprocess broadens secret exposure and combines badly with the same function's runtime package installation and re-execution behavior.

Missing User Warnings

High
Confidence
98% confidence
Finding
The buy/sell commands place orders immediately after parsing arguments and unlocking trading, with no confirmation prompt, dry-run mode, or policy guardrails. Even in paper trading, order placement is a sensitive action; in agent workflows, accidental or manipulated invocation can trigger unauthorized financial operations and normalize unsafe patterns that may later be reused against real trading contexts.

Missing User Warnings

High
Confidence
97% confidence
Finding
The cancel command performs an irreversible trading action without confirmation or secondary approval. In an agent environment, a single unintended invocation can disrupt strategy execution or interfere with active positions, making silent cancellation a meaningful integrity risk.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README explicitly promotes building a 'full-automatic AI trading system' and describes periodic monitoring followed by autonomous buy actions, but it does not provide a prominent warning that these commands can place orders and materially affect an account state. Even though the README says this is paper trading, autonomous order placement in a trading skill is still safety-sensitive because users or downstream agents may normalize unattended execution without understanding the operational and financial consequences.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises shell and environment-dependent behavior but does not declare any explicit tool scope or permissions boundaries. In practice, this makes the skill capable of executing local commands, reading environment variables, and performing dependency installation without clear policy constraints, increasing the chance of unintended command execution or secret exposure.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill metadata frames the capability as quote/position/order paper trading, yet the body documents additional historical K-line and financial-statement retrieval features. This inconsistency weakens informed consent and security review because the effective data-access surface is larger than the declared purpose.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger condition is broad: 'when the user needs quotes, positions, orders, fills, or placing orders, call this skill.' Without tighter scope boundaries or confirmation gates, an agent may invoke the skill too readily, including for sensitive trade-related actions, increasing the risk of unintended execution.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill includes buy, sell, and cancel operations but does not present an explicit warning or confirmation requirement for account-impacting actions. Even though it claims to restrict execution to paper trading, these are still state-changing financial operations, and weak UX safeguards can lead to unintended orders, cancellations, or over-trusting a similar pattern in future real-trading variants.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The skill expands into third-party financial data collection through AkShare and upstream data providers unrelated to the core paper-trading workflow. Adding external data sources increases network/data provenance risk, may expose user activity to additional services, and broadens the trust boundary beyond what the user expects from a Futu paper-trading skill.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_python_version(python_cmd):
    try:
        output = subprocess.check_output(
            [python_cmd, "-c", "import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}')"],
            text=True,
        ).strip()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file contains many user-facing error and next-step messages written only in Chinese, with no mechanism for users to choose language or locale. This creates a natural-language policy issue because the skill effectively forces a specific language for interaction without opt-in or documented regional justification.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The skill self-manages a virtual environment and installs packages at runtime, which is outside the minimal needs of a paper-trading skill and materially enlarges the execution and supply-chain attack surface. In an agent context, runtime environment mutation is especially risky because it can fetch and execute new code during normal use.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not is_compatible_python(venv_version):
            shutil.rmtree(venv_dir, ignore_errors=True)
    if not python_path.exists():
        subprocess.check_call([python_cmd, "-m", "venv", str(venv_dir)])
    if not pip_path.exists():
        raise RuntimeError("虚拟环境创建失败")
    requirements = base_dir / "requirements.txt"
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not pip_path.exists():
        raise RuntimeError("虚拟环境创建失败")
    requirements = base_dir / "requirements.txt"
    subprocess.check_call([str(pip_path), "install", "-r", str(requirements)])
    env = os.environ.copy()
    env["FUTU_SKILL_VENV"] = "1"
    subprocess.check_call([str(python_path), str(Path(__file__).resolve()), *sys.argv[1:]], env=env)
Confidence
93% confidence
Finding
The skill performs runtime dependency installation by invoking pip inside its own managed virtual environment. This executes package installation code and dependency resolution at run time, expanding the trust boundary to package indexes and local requirement contents, which is unnecessary for a paper-trading skill and can lead to code execution or supply-chain compromise.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
subprocess.check_call([str(pip_path), "install", "-r", str(requirements)])
    env = os.environ.copy()
    env["FUTU_SKILL_VENV"] = "1"
    subprocess.check_call([str(python_path), str(Path(__file__).resolve()), *sys.argv[1:]], env=env)
    sys.exit(0)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
Adding AkShare introduces a second external data source and dependency chain unrelated to the stated Futu paper-trading function. That increases attack surface, trust assumptions, and data-flow complexity, especially since the fallback is automatic and may surprise users expecting only Futu-backed behavior.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The trade unlock password is sourced directly from environment variables without prominent disclosure, consent, or guidance about secret handling. In shared agent runtimes, environment variables are often broadly available to subprocesses and logs, so using them for a trading credential increases risk of credential exposure and unauthorized trade operations.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The implemented capability exceeds the declared purpose: besides quotes, positions, and paper orders, it exposes financial statement and indicator retrieval paths. Scope expansion matters in agent skills because users and orchestrators may grant trust based on the manifest, and undisclosed capabilities increase the chance of inappropriate data access or unintended invocation.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
Nearly all user-facing instructions and descriptions are presented only in Chinese, and the README does not offer an English alternative or state that the skill is intentionally limited to Chinese-speaking users. This can violate language/locale policy expectations when no user opt-in or justified locale restriction is provided.

Unpinned Dependencies

Low
Category
Supply Chain
Content
futu-api>=1.0.0
akshare>=1.18.0
Confidence
94% confidence
Finding
The dependency specification uses a lower-bound only constraint, which allows installation of any newer version of futu-api, including releases with breaking changes or a compromised upstream package version. In a trading skill that queries market data and places paper trades, dependency drift can affect integrity of trading logic and increase supply-chain risk.

Unpinned Dependencies

Low
Category
Supply Chain
Content
futu-api>=1.0.0
akshare>=1.18.0
Confidence
94% confidence
Finding
The dependency specification for akshare is unpinned and permits arbitrary newer versions to be installed, which can introduce malicious code, vulnerable transitive dependencies, or incompatible behavior without review. Because this skill operates in a financial context, unexpected library changes can impact data correctness and decision-making, making the supply-chain exposure more significant.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
def find_quote_handler(quote_ctx, names):
    for name in names:
        if hasattr(quote_ctx, name):
            return getattr(quote_ctx, name)
    return None
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
def find_trade_handler(trade_ctx, names):
    for name in names:
        if hasattr(trade_ctx, name):
            return getattr(trade_ctx, name)
    return None
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
except Exception:
        return None
    for enum_name in enum_names:
        enum_cls = getattr(futu, enum_name, None)
        if enum_cls is None:
            continue
        for candidate in candidates:
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.