Back to skill

Security audit

OpenD CLI for MooMoo

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it can affect live trading accounts and store trading credentials with safeguards that are mostly advisory rather than enforced.

Review carefully before installing, especially for hosted or shared-agent use. Keep it limited to simulated trading unless you add an explicit live-trade approval step, use managed secret injection instead of keyring or local config files, avoid OPEND_SDK_PATH unless the directory is trusted, and pin/review the trading SDK dependencies.

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)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:13
Finding

Unpinned Third-Party Dependencies Create a Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:13-17
Vulnerability Type: Unpinned third-party dependency installation
Risk Level: Medium

Vulnerable Code

markdown
- Install one provider SDK: `moomoo` or `futu`.
- Prefer OpenClaw-managed secret refs for hosted use:
  - `export OPEND_PASSWORD_SECRET_REF='{"source":"env","id":"MOOMOO_PASSWORD"}'`
  - Provide the actual `MOOMOO_PASSWORD` through OpenClaw gateway secret injection, not plain shell export.
- Optional local-only helpers: `pip install keyring cryptography`.

Technical Analysis

The installation instructions identify third-party packages only by mutable package names. They do not specify reviewed versions, cryptographic hashes, a lock file, a constraints file, or an explicitly trusted package index.

Package names such as moomoo, futu, keyring, and cryptography are resolved at installation time. Consequently, the code installed by a user can differ from the code that was reviewed during this audit. A compromised publisher account, malicious future release, package-index substitution, or dependency-confusion condition could introduce arbitrary code.

This risk is particularly important because the dependencies are imported into a process that can access trading credentials and issue real financial transactions.

Attack Path

  1. An attacker compromises an upstream package, its publisher account, its dependency chain, or the package index used by the victim.
  2. The attacker publishes a malicious version under one of the package names recommended by the Skill.
  3. A user follows the installation instructions without pinning or hash verification.
  4. The malicious package executes during installation or when imported by the Skill.
  5. The package reads available credentials, tampers with market data, or invokes trading functionality under the user's authority.

Impact Assessment

Malicious dependency code would execute w ...[truncated 375 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin every direct dependency to a reviewed version.
  • Publish a lock or constraints file containing cryptographic hashes.
  • Identify the authoritative package publisher and trusted package index.
  • Require hash-verified installation, such as pip install --require-hashes.
  • Install dependencies in an isolated virtual environment with minimal privileges.
  • Add automated dependency vulnerability and provenance checks to release validation.
  • Review and pin transitive dependencies where practical.
  • Document an upgrade process that requires security review before changing pinned versions.

T09 · Insecure Skill Coding Practices

Warning
Location
opend_core.py:16
Finding

Environment-Controlled Python Import Path Enables Arbitrary Code Execution

Content
View full analysis

Vulnerability Details

File Location: opend_core.py:16-31
Vulnerability Type: Unsafe dynamic import path manipulation
Risk Level: Medium

Vulnerable Code

python
def load_sdk():
    """Load moomoo/futu SDK with optional explicit path support."""
    sdk_path = os.getenv("OPEND_SDK_PATH")
    if sdk_path and sdk_path not in sys.path:
        print(
            "Warning: OPEND_SDK_PATH is set. Only load SDK code from a trusted location.",
            file=sys.stderr,
        )
        sys.path.insert(0, sdk_path)

    try:
        import moomoo as ft  # type: ignore

        return ft
    except Exception:
        pass

    try:
        import futu as ft  # type: ignore

Technical Analysis

OPEND_SDK_PATH is read from the environment and inserted at the beginning of sys.path. Python subsequently imports the predictable module names moomoo and futu. Because the attacker-controlled directory has import precedence, a file such as moomoo.py or a package named moomoo in that directory will execute during import.

The warning printed to standard error does not enforce trust, validate the path, check ownership or permissions, or authenticate the imported package. Any party that can influence the environment variable or write to the selected directory can convert this configuration feature into arbitrary Python code execution.

The broad exception handler around the first import also allows a malicious or defective moomoo package to execute partially, raise an exception, and then cause a second import attempt.

Attack Path

  1. An attacker gains control over OPEND_SDK_PATH, a deployment configuration source, or a directory already referenced by that variable.
  2. The attacker creates a malicious moomoo.py, moomoo package, futu.py, or futu package in that directory.
  3. A user or agent invokes any CLI command that constructs OpenDClient.
  4. load_sdk() p ...[truncated 671 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove OPEND_SDK_PATH support from production deployments and install the SDK through a controlled dependency mechanism.
  • If custom paths are essential, resolve them to canonical absolute paths and enforce an explicit allowlist.
  • Reject paths that are group-writable, world-writable, symlinks, or owned by an unexpected user.
  • Verify the package's expected location, version, publisher, and cryptographic integrity before import.
  • Avoid prepending arbitrary paths to global sys.path.
  • Run the Skill in an isolated environment with minimal filesystem, credential, and network permissions.
  • Catch only expected import failures rather than all exceptions, so partially executing malicious or defective modules cannot be silently ignored.

T09 · Insecure Skill Coding Practices

Note
Location
setup_config.py:12
Finding

Non-Atomic Credential-Key Creation Permits Disclosure and Symlink Overwrite

Content
View full analysis

Vulnerability Details

File Location: setup_config.py:12-22
Vulnerability Type: Unsafe sensitive-file creation
Risk Level: Low

Vulnerable Code

python
def main():
    password = getpass.getpass("Enter MooMoo API password: ")
    config = {'password': password}
    key = generate_key()
    save_encrypted_config(config, key)
    KEY_PATH.write_text(key.decode(), encoding="utf-8")
    KEY_PATH.chmod(0o600)
    print("Encrypted config saved to config.enc")
    print("Legacy credential warning: config.enc is not the recommended OpenClaw deployment mode.")
    print(f"Generated MOOMOO_CONFIG_KEY saved to {KEY_PATH} with mode 600.")
    print("Move that key into a secret manager or OS keychain before using the config method.")

Technical Analysis

The decryption key is written with Path.write_text() and restricted to mode 0600 only afterward. The file is initially created according to the process umask, creating a race window in which it may have broader permissions than intended.

Path.write_text() also follows existing symbolic links and truncates existing files. If the setup script runs in a directory writable by another user, an attacker can pre-create config.key as a symbolic link. The script will then write the Fernet key to the link target before changing the target's permissions.

The encrypted configuration file is also created through a normal write operation, but disclosure of the Fernet key is the more significant issue because possession of both config.key and config.enc permits recovery of the trading password.

Attack Path

  1. The victim runs setup_config.py in a shared or attacker-influenced working directory.
  2. The attacker either monitors newly created files or pre-creates config.key as a symbolic link to a writable target.
  3. KEY_PATH.write_text() creates or follows the file using umask-derived permissions.
  4. Before chmod(0o600) completes, an ...[truncated 709 chars]
Remediation
View remediation

Remediation Suggestions

  • Create the key atomically with mode 0600, using os.open() with O_WRONLY | O_CREAT | O_EXCL and, where supported, O_NOFOLLOW.
  • Write through the returned file descriptor rather than reopening the path.
  • Reject pre-existing files and symbolic links.
  • Store credential material in a trusted, private directory rather than the current working directory.
  • Apply restrictive directory permissions before creating either config.key or config.enc.
  • Use atomic temporary-file creation and rename for the encrypted configuration.
  • Prefer the documented gateway-managed secret mechanism or OS keychain instead of maintaining a decryption key beside the encrypted data.
  • Verify file ownership and permissions before loading legacy configuration material.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (29)

Credential Access

High
Category
Privilege Escalation
Confidence
78% confidence
Finding

If no stored password exists, the function interactively prompts the operator and then persists the credential into the local keyring. In an agentic or hosted environment, unexpected interactive secret capture can lead to insecure operational practices, accidental storage on untrusted hosts, or collection of live trading credentials outside the intended gateway-managed secret path.

Content

Scanner excerpt · credentials.py (reported line 74)May include surrounding context.

python
if keyring is None:
        raise RuntimeError("python package 'keyring' is not available")

    password = keyring.get_password(SERVICE_NAME, PASSWORD_KEY)
    if not password:
        # Prompt to set it
        password = getpass.getpass("Enter MooMoo API password to store in keyring: ")

Credential Access

High
Category
Privilege Escalation
Confidence
80% confidence
Finding

Persisting a newly entered password into the host keyring can create unauthorized long-lived secret storage, especially on shared workstations, CI runners, or hosted agent systems. For a trading skill, this increases the blast radius of host compromise because account credentials may remain accessible after execution.

Content

Scanner excerpt · credentials.py (reported line 77)May include surrounding context.

python
password = keyring.get_password(SERVICE_NAME, PASSWORD_KEY)
    if not password:
        # Prompt to set it
        password = getpass.getpass("Enter MooMoo API password to store in keyring: ")
        keyring.set_password(SERVICE_NAME, PASSWORD_KEY, password)
    return password

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The CLI exposes order placement and supports --trd-env REAL without any explicit confirmation, warning, or secondary safety check before submitting a live trade. In an agentic trading skill, this materially increases the risk of accidental or prompt-induced real-money transactions, especially because the interface is designed for automation rather than deliberate human review.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 13)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 15)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 69)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 70)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 71)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 72)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 78)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 130)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 131)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 132)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · credentials.py (reported line 145)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · opend_cli.py (reported line 96)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · place_order.py (reported line 11)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · place_order_keyring.py (reported line 2)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · place_order_keyring.py (reported line 9)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · query_positions.py (reported line 11)May include surrounding context.

python
#!/usr/bin/env python3
"""Example wrapper for keyring-based credential place-order."""

import sys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup_config.py (reported line 23)May include surrounding context.

python
print("Encrypted config saved to config.enc")
    print("Legacy credential warning: config.enc is not the recommended OpenClaw deployment mode.")
    print(f"Generated MOOMOO_CONFIG_KEY saved to {KEY_PATH} with mode 600.")
    print("Move that key into a secret manager or OS keychain before using the config method.")

if __name__ == "__main__":
    main()

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill exposes powerful capabilities through its documented interfaces, including shell execution, environment-variable access, and local file read/write behavior for credentials and config material, but it does not declare any explicit tool scope restrictions. In an agent setting, this increases the chance that an orchestrator grants broader-than-necessary access, enabling unintended command execution, secret exposure, or modification of local sensitive files during trading workflows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Order cancellation can be executed against live accounts with no explicit warning or confirmation path. While canceling is generally less severe than placing a new order, unauthorized or accidental cancellation can disrupt trading strategy, create financial loss, or interfere with intended risk controls in a live environment.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module prepends an environment-controlled filesystem path to sys.path and then imports a Python package from that location. In an agentic trading skill, this is dangerous because an attacker who can influence OPEND_SDK_PATH or the filesystem contents can cause arbitrary Python code execution under the agent's privileges, potentially stealing credentials or placing unauthorized trades.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file exposes direct live-trading actions for place_order and cancel_order with no built-in confirmation, policy gate, or explicit safeguard at the point of execution. In a trading agent context this materially increases the risk of accidental, prompt-injected, or unauthorized order execution, especially because the same code can operate in non-simulated environments after unlocking trading.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest explicitly mentions simulated or live order placement, but does not mention order modification or cancellation. This file adds a distinct trading capability by calling modify_order with CANCEL, which goes beyond the described operations rather than being a necessary implementation detail of placing orders.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.