Back to skill

Security audit

longbridge

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real LongPort brokerage CLI, but it tells AI agents to bypass trade confirmations while using stored brokerage credentials.

Install only if you intend to let an AI-accessible CLI read your Longbridge account data. Keep the default read-only mode unless you are deliberately trading, avoid using --yes/-y for live orders, prefer a paper or read-only profile for agent workflows, and review the profile/env-file handling and dependency pinning before using it with a real brokerage account.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:121
Finding
AI Agent Instructions Recommend Bypassing Live-Trade Confirmation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:121-122, 145`; implemented by `longbridge_cli/commands/order.py:63-78, 98-113` **Vulnerability Type**: Agent-directed safety-control bypass **Risk Level**: High ### Evidence ```text # Skip confirmation prompt (recommended for AI Agent programmatic calls) longbridge buy AAPL.US --qty 100 --price 180.0 --yes ``` ```python @click.option("--yes", "-y", is_flag=True, help="Skip interactive confirmation") @click.pass_context def buy_cmd(ctx, symbol, qty, price, output_json, yes): require_trade_enabled() if not yes: click.confirm( f"Confirm purchase of {symbol}, quantity {qty}, limit price {price}?", abort=True, ) try: trade_ctx = TradeContext(get_config(ctx.obj.get("profile"))) resp = trade_ctx.submit_order( symbol, OrderType.LO, OrderSide.Buy, qty, TimeInForceType.Day, submitted_price=Decimal(str(price)), ) ``` The corresponding sell command uses the same `--yes` bypass before calling `submit_order()`. ### Technical Analysis The Skill explicitly recommends that an AI Agent supply `--yes` for programmatic trading. In the implementation, that flag skips `click.confirm()` and permits immediate submission of a brokerage order after the persistent `LONGBRIDGE_TRADE_ENABLED=true` setting is detected. The environment-variable gate is a useful default safeguard, but it is not transaction-specific. Once trading has been enabled, the confirmation prompt is the final control through which a user can verify the account, symbol, side, quantity, and price. Recommending that an Agent bypass it weakens the safety boundary around consequential financial actions. This is particularly dangerous where an Agent may process ambiguous instructions, untrusted market text, compromised contextual data, or prompt-injected content. ### Attack Path 1. The user or system enables ...[truncated 1083 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the instruction recommending `--yes` for AI Agent calls. 2. Require explicit, transaction-specific human approval for every live order. 3. Disable `--yes` when an Agent or other noninteractive environment is detected. 4. If noninteractive operation is necessary, limit it to a separately identified paper-trading account. 5. Display and verify the profile, account environment, side, symbol, quantity, price, estimated notional value, and currency immediately before submission. 6. Introduce configurable per-order and daily notional limits. 7. Consider short-lived approval tokens bound to the exact transaction parameters rather than a persistent environment-variable permission. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
longbridge_cli/config.py:21
Finding
Unvalidated Profile Name Allows Environment-File Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `longbridge_cli/cli.py:29-43`; `longbridge_cli/config.py:21-46` **Vulnerability Type**: Path traversal and unintended configuration loading **Risk Level**: Medium ### Evidence ```python @click.option( "--profile", default=None, help="Account profile used to load a .{profile}.env credential file", ) @click.pass_context def cli(ctx, profile): ctx.ensure_object(dict) ctx.obj["profile"] = profile ``` ```python filename = f".{profile}.env" if profile else ".env" env_path: Path | None = None for base in [Path.cwd(), Path.home()]: candidate = base / filename if candidate.is_file(): env_path = candidate break if env_path is None: if profile is not None: raise FileNotFoundError( f"Profile '{profile}' environment file was not found. " f"Create {filename} in the current or home directory." ) return with open(env_path, encoding="utf-8") as f: for line in f: line = line.strip() if not line or line.startswith("#") or "=" not in line: continue key, _, value = line.partition("=") key = key.strip() value = value.strip().strip('"').strip("'") if key and key not in os.environ: os.environ[key] = value ``` ### Technical Analysis The `--profile` option accepts arbitrary text and interpolates it directly into a filename. `pathlib` path joining does not guarantee that the resulting path remains beneath `Path.cwd()` or `Path.home()` when the interpolated value contains path separators or traversal components. For example, a profile resembling `../target` produces a path resembling: ```text <current-directory>/../target.env ``` If the resulting file exists, the loader reads it and imports every parsed key into the current process environment. The code does not restrict profile names to identifiers, resolve and validate the final path against an approved direct ...[truncated 1581 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict profile names to a conservative allowlist, such as `^[A-Za-z0-9_-]+$`. 2. Reject profile values containing `/`, `\`, `..`, drive prefixes, null bytes, or path separators. 3. Store profiles in one dedicated configuration directory rather than searching the working directory and home directory. 4. Resolve both the base directory and candidate path, then verify that the candidate's parent is exactly the approved profile directory. 5. Import only explicitly supported keys: - `LONGBRIDGE_APP_KEY` - `LONGBRIDGE_APP_SECRET` - `LONGBRIDGE_ACCESS_TOKEN` - `LONGBRIDGE_TRADE_ENABLED` 6. Reject symlinks or verify the resolved target remains under the approved directory. 7. Require restrictive credential-file permissions and warn when files are readable by other users. ]]>

T08 · Insecure Dependencies

Warning
Location
pyproject.toml:1
Finding
Security-Critical Brokerage Dependencies Are Not Reproducibly Pinned<![CDATA[ ## Vulnerability Details **File Location**: `pyproject.toml:1-14`; `requirements.txt:1-3` **Vulnerability Type**: Mutable third-party dependency resolution **Risk Level**: Medium ### Evidence ```toml [build-system] requires = ["setuptools>=42", "wheel"] build-backend = "setuptools.build_meta" [project] name = "longbridge-cli" version = "1.0.0" description = "LongPort OpenAPI CLI" requires-python = ">=3.9" dependencies = [ "longbridge", "click>=8.0", "rich>=13.0", ] ``` ```text longbridge click>=8.0 rich>=13.0 ``` ### Technical Analysis The project does not pin the `longbridge` SDK to a reviewed version and supplies no lockfile or package hashes. The lower-bound-only constraints on `click` and `rich` likewise allow future versions to be selected automatically. Build dependencies are also mutable. This is especially sensitive because the Longbridge SDK receives the application key, application secret, and access token and provides the methods used to read account data and submit brokerage orders. A compromised, malicious, or unexpectedly incompatible future release would be installed without a source change in this project. The audit did not establish that any currently referenced package is malicious. The confirmed issue is the absence of reproducible dependency controls around a credential-bearing, trade-capable application. ### Attack Path 1. A dependency publisher account or upstream distribution channel is compromised, or an incompatible future version is released. 2. A user follows the Skill installation instruction and runs `uv tool install` for the project. 3. The resolver selects the newly available dependency because no exact reviewed version or hash is required. 4. The package executes during installation, import, or runtime. 5. Malicious dependency code can access the CLI process, environment credentials, account-query results, and SDK call flow. 6. Depending on the credentials and configuration, it could disclose secret ...[truncated 555 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin all runtime and build dependencies to reviewed exact versions. 2. Generate and commit a lockfile supported by the chosen installer. 3. Use package hashes where supported to verify distribution integrity. 4. Upgrade dependencies through a controlled review process rather than resolving arbitrary future releases during installation. 5. Run dependency vulnerability and provenance checks in continuous integration. 6. Review Longbridge SDK release notes and source changes before each upgrade. 7. Build and publish from a controlled environment with a software bill of materials and signed artifacts where practical. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
longbridge_cli/commands/order.py:59
Finding
Live Order Parameters Lack Local Range and Finiteness Validation<![CDATA[ ## Vulnerability Details **File Location**: `longbridge_cli/commands/order.py:59-83, 94-118` **Vulnerability Type**: Insufficient validation of consequential financial inputs **Risk Level**: Medium ### Evidence ```python @click.command("buy") @click.argument("symbol") @click.option("--qty", required=True, type=int, help="Purchase quantity") @click.option("--price", required=True, type=float, help="Limit price") @click.option("--json", "output_json", is_flag=True, help="Output JSON") @click.option("--yes", "-y", is_flag=True, help="Skip interactive confirmation") @click.pass_context def buy_cmd(ctx, symbol, qty, price, output_json, yes): require_trade_enabled() if not yes: click.confirm( f"Confirm purchase of {symbol}, quantity {qty}, limit price {price}?", abort=True, ) try: trade_ctx = TradeContext(get_config(ctx.obj.get("profile"))) resp = trade_ctx.submit_order( symbol, OrderType.LO, OrderSide.Buy, qty, TimeInForceType.Day, submitted_price=Decimal(str(price)), ) ``` ```python @click.command("sell") @click.argument("symbol") @click.option("--qty", required=True, type=int, help="Sale quantity") @click.option("--price", required=True, type=float, help="Limit price") @click.option("--json", "output_json", is_flag=True, help="Output JSON") @click.option("--yes", "-y", is_flag=True, help="Skip interactive confirmation") @click.pass_context def sell_cmd(ctx, symbol, qty, price, output_json, yes): require_trade_enabled() if not yes: click.confirm( f"Confirm sale of {symbol}, quantity {qty}, limit price {price}?", abort=True, ) try: trade_ctx = TradeContext(get_config(ctx.obj.get("profile"))) resp = trade_ctx.submit_order( symbol, OrderType.LO, OrderSide.Sell, qty, TimeInForceType.Day ...[truncated 2164 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use `click.IntRange(min=1, max=<approved-limit>)` for quantity. 2. Parse prices directly as `Decimal` rather than binary `float`. 3. Reject non-finite, zero, and negative prices. 4. Enforce instrument-specific price precision, tick size, and lot size. 5. Validate symbol syntax and normalize market suffixes before submission. 6. Calculate estimated notional value and enforce configurable per-order and daily limits. 7. Perform validation before presenting the confirmation prompt so the user approves canonical values. 8. Retain server-side validation as defense in depth, but do not treat it as a substitute for local checks. 9. Add tests for zero, negative, excessive, non-finite, malformed, and precision-invalid inputs. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (41)

Credential Access

High
Category
Privilege Escalation
Content
|----------|----------|-------------|
| `LONGBRIDGE_APP_KEY` | ✅ | App Key |
| `LONGBRIDGE_APP_SECRET` | ✅ | App Secret |
| `LONGBRIDGE_ACCESS_TOKEN` | ✅ | Access Token |
| `LONGBRIDGE_TRADE_ENABLED` | Optional | Set to `true` to enable trading (default: read-only) |

---
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
There is a clear mismatch between the description and the supplied code chunk. The description claims a full-featured LongPort CLI covering quotes, holdings, orders, and market analytics. However, the actual code is only an `__init__.py` file with a package docstring and no executable logic or exposed functionality. Based on the provided code alone, none of the declared capabilities are present.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
代码文件是 `commands/quote.py`,从实现上看只注册了 `quote`、`depth`、`trades`、`candlesticks`、`info` 五个命令,全部依赖 `QuoteContext` 获取行情或标的静态信息。没有看到账户上下文、订单上下文、交易接口、持仓查询或任何资金/期权相关调用。因此,若将“该 skill”的声明理解为这段代码所代表的能力,则声明明显比实际代码宽得多,尤其把账户和订单管理说成已提供,构成描述与行为不一致。虽然声明中的行情查询部分与代码一致,但整体用途被显著夸大,因此应判定为 mismatch。

Vague Triggers

High
Confidence
97% confidence
Finding
The trigger language is extremely broad and includes ordinary requests like checking a stock price or 'help me place an order,' causing the skill to auto-activate in many ambiguous situations. In this context the skill has access to brokerage credentials and trading commands, so overbroad invocation materially raises the risk of unintended access to account data or accidental execution of sensitive financial actions.

Missing User Warnings

High
Confidence
98% confidence
Finding
The documentation explicitly recommends using --yes/-y to bypass trade confirmations for AI agent automation, without strong safeguards or warnings. In a brokerage skill, this removes a key human-in-the-loop control and can enable erroneous or unauthorized buy, sell, or cancel actions with immediate financial consequences.

Credential Access

High
Category
Privilege Escalation
Content
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
# ---------------------------------------------------------------------------
# .env 加载(CLI 包自包含,不依赖 trader 包)
# ---------------------------------------------------------------------------

def _load_dotenv_for_profile(profile: str | None = None) -> None:
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
profile 非空 + 文件不存在 → 抛 FileNotFoundError。
    已存在的环境变量不会被覆盖。
    """
    filename = f".{profile}.env" if profile else ".env"
    env_path: Path | None = None
    for base in [Path.cwd(), Path.home()]:
        candidate = base / filename
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Session Persistence

Medium
Category
Rogue Agent
Content
#### Method 1: .env file (recommended)

Create a `.env` file in the current directory or home directory (`~/.env`):

```bash
LONGBRIDGE_APP_KEY=your_app_key
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Cancel order (confirmation prompt)
longbridge cancel 701234567890

# Skip confirmation for programmatic / scripted use
longbridge buy AAPL.US --qty 100 --price 180.0 --yes
longbridge sell 700.HK --qty 500 --price 320.0 -y
```
Confidence
88% confidence
Finding
The README explicitly documents `--yes`/`-y` to bypass confirmation for buy/sell operations, enabling non-interactive trade execution. In an AI-agent context, this materially increases the chance of autonomous or accidental order placement if the agent is permitted to invoke the CLI with trading enabled.

Session Persistence

Medium
Category
Rogue Agent
Content
Copy `SKILL.md` to your OpenClaw skills directory to register it as a Clawdbot Skill:

```bash
mkdir -p ~/.openclaw/skills/longbridge-cli
cp SKILL.md ~/.openclaw/skills/longbridge-cli/SKILL.md
```
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
Copy `SKILL.md` to your OpenClaw skills directory to register it as a Clawdbot Skill:

```bash
mkdir -p ~/.openclaw/skills/longbridge-cli
cp SKILL.md ~/.openclaw/skills/longbridge-cli/SKILL.md
```
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```bash
mkdir -p ~/.openclaw/skills/longbridge-cli
cp SKILL.md ~/.openclaw/skills/longbridge-cli/SKILL.md
```

Once installed, Claude can invoke longbridge-cli commands automatically when you ask about account balances, positions, quotes, or orders.
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```bash
mkdir -p ~/.openclaw/skills/longbridge-cli
cp SKILL.md ~/.openclaw/skills/longbridge-cli/SKILL.md
```

Once installed, Claude can invoke longbridge-cli commands automatically when you ask about account balances, positions, quotes, or orders.
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Session Persistence

Medium
Category
Rogue Agent
Content
### Notes

- **Read-only mode**: `buy`/`sell`/`cancel` require `LONGBRIDGE_TRADE_ENABLED=true`
- **Trade confirmation**: Even with trade permission enabled, all write commands prompt for confirmation before executing. Use `--yes` / `-y` to skip the prompt for scripted or programmatic use
- **Multi-account profiles**: Use `longbridge --profile <name>` to load `.<name>.env` credentials (e.g., `--profile paper` loads `.paper.env`). Useful for switching between paper trading and live accounts
- **HK symbol format**: Must use 4-digit format, e.g. `0700.HK` (leading zero required)
- **Error handling**: SDK exceptions are caught and displayed as friendly messages
Confidence
80% confidence
Finding
The combination of persistent multi-account profile files (`.<name>.env`) and documented non-interactive trade execution increases the blast radius of mistakes: an agent or script can repeatedly access stored live credentials and place trades without human confirmation. In a trading skill, this persistence is more dangerous than in a read-only data tool because it supports durable access to high-impact actions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares access to sensitive environment variables containing API credentials but does not define any explicit tool scope or permission boundary. In an agent setting, this increases the chance that secrets are exposed to components or workflows beyond what is necessary, especially since the skill also supports account and trading operations.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The module's docstrings, help text, table headers, and titles are all presented in Chinese, with no indication that users can select another language or that the tool is intentionally limited to a Chinese-speaking locale. This can violate language/locale policy when a skill forces a specific language without user opt-in or documented justification.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The command retrieves account balance and net asset information via `TradeContext(...).account_balance()` and then prints it, but the code provides no explicit warning, confirmation, or disclosure that sensitive financial account data will be accessed and displayed. For code files, safety-relevant access to sensitive data should have some visible disclosure unless clearly covered elsewhere.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The `positions` command fetches portfolio holdings using `stock_positions()` and outputs symbols, quantities, and cost basis data, which are sensitive financial details. There is no confirmation prompt, disclosure message, or warning in the command text indicating that personal portfolio data will be retrieved and shown.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The `funds` command retrieves fund holding details, including holdings, valuation, and cost data, then prints them without any explicit disclosure to the user. This is sensitive account information, and the code does not include a warning, confirmation, or explanatory notice.

Static analysis

No suspicious patterns detected.