Back to skill

Security audit

bot-trade

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed simulated-trading skill, but it needs review because it can persist API credentials and enable leveraged trading behavior without clear confirmation and safety boundaries.

Review this skill before installing if the agent may act autonomously. Only allow it to place or close trades after explicit user approval or well-defined limits, store the API key in a protected secret store or a 0600 file, and verify any close-position implementation always uses reduce_only and validates quantity.

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

Warning
Location
SKILL.md:424
Finding
API Credential Stored Without Restrictive File Permissions## Vulnerability Details **File Location**: `SKILL.md`, lines 424–429 **Vulnerability Type**: Plaintext sensitive credential with insufficient permission hardening **Risk Level**: Medium **Vulnerable Code:** ```python os.makedirs(os.path.dirname(self.credentials_path), exist_ok=True) with open(self.credentials_path, "w") as f: json.dump({ "api_key": data["api_key"], "bot_id": data["bot_id"] }, f) ``` The path is initialized as follows at line 406: ```python self.credentials_path = os.path.expanduser("~/.config/mosstrade/credentials.json") ``` ### Technical Analysis The implementation stores a bearer API key in a plaintext JSON file. The directory and file are created with process-default permissions rather than explicit restrictive modes. If the process has a permissive `umask`, another local user may be able to read the credential. The code also does not guard against symbolic-link replacement or use atomic file creation. In a locally hostile environment, an attacker who can manipulate the destination path may attempt to redirect the write or interfere with credential storage. Reading one dedicated credential file and sending its key to the declared MossTrade API are consistent with the Skill's authenticated simulated-trading functionality. No evidence indicates that the key is sent to unrelated services. The security issue is the local storage implementation, which is less restrictive than necessary. ### Attack Path 1. The Skill enrolls a bot and receives an API key from the declared MossTrade API. 2. It creates `~/.config/mosstrade` and writes `credentials.json` using default filesystem permissions. 3. On a system with permissive defaults, another local user or compromised process reads the file. 4. The attacker extracts the bearer API key. 5. The attacker uses the key in the `Authorization` header when calling authenticated MossTrade endpoints. 6. The attacker can imperson ...[truncated 527 chars]
Remediation
## Remediation Suggestions - Create the credential directory with mode `0700`. - Create the credential file atomically with mode `0600`, rather than relying on the process `umask`. - Refuse to follow symbolic links when creating or replacing the file. - Write to a securely created temporary file in the same directory, set its permissions, flush it, and atomically rename it into place. - Prefer an operating-system credential manager or secret store when available. - Never include the API key in logs, exception messages, or diagnostic output. - Validate the ownership and permissions of an existing credential file before reading it.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:463
Finding
Position-Closing Logic Can Open an Unintended Reverse Position## Vulnerability Details **File Location**: `SKILL.md`, lines 463–486 **Vulnerability Type**: Unsafe trading-state transition caused by omitted reduction-only control **Risk Level**: Medium **Vulnerable Code:** ```python def close_position(self, symbol, quantity, leverage, reason=""): """平仓 - 根据当前持仓方向自动选择""" portfolio = self.get_portfolio() for pos in portfolio.get("positions", []): if pos["symbol"] == symbol: # 反向下单平仓 side = "sell" if pos["side"] == "long" else "buy" return self._place_order(symbol, side, quantity, leverage, reason) return {"error": "no_position", "message": f"没有 {symbol} 持仓"} def _place_order(self, symbol, side, quantity, leverage, reason): """下单""" resp = requests.post( f"{self.api_base}/order/place", headers=self._headers(), json={ "symbol": symbol, "side": side, "type": "market", "quantity": quantity, "leverage": leverage, "decision_log": {"reason": reason} } ) return resp.json() ``` ### Technical Analysis The Skill's documentation states that closing orders should set `reduce_only: true` to prevent a reverse position. However, the reusable `close_position` implementation calls `_place_order` without such a parameter, and the submitted JSON does not contain `reduce_only`. Closing a position by merely placing an opposite-side market order is unsafe. If the requested quantity is greater than the current position, the excess can become a new position in the opposite direction. A race condition also exists between retrieving the portfolio and submitting the order: the position may be reduced or closed by another operation after the snapshot is read. The flaw is particularly consequential because the documented API permits leverage from 10x to 1000x. It is a correctness and security defect in the ...[truncated 1039 chars]
Remediation
## Remediation Suggestions - Extend `_place_order` with an explicit `reduce_only` argument and always pass `True` from `close_position`. - Include `"reduce_only": True` in every position-closing request. - Parse the current position quantity as a fixed-precision decimal and reject any requested closing quantity that exceeds it. - Prefer a server-side close-position endpoint or position identifier if the API provides one. - Handle concurrent state changes by using server-side reduction-only enforcement rather than relying solely on a prior portfolio snapshot. - Validate HTTP status codes and API error fields before reporting that the position was closed. - Add tests for excessive quantities, stale portfolio data, partial fills, already-closed positions, and concurrent close requests.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Credential Access

High
Category
Privilege Escalation
Content
⚠️ **重要:保存 api_key!** 这是你唯一的身份凭证,后续所有请求都需要它。

**建议保存位置:** `~/.config/mosstrade/credentials.json`
```json
{
  "api_key": "arena_sk_xxx",
Confidence
97% confidence
Finding
The documentation recommends storing the API key in a plaintext file under the user's home directory. Any local process, plugin, backup system, or accidental file disclosure could expose the bearer token, allowing unauthorized portfolio access and trading actions against the associated bot.

Credential Access

High
Category
Privilege Escalation
Content
class MossTradeAgent:
    def __init__(self):
        self.api_base = "https://lark.openclaw-ai.cc/api/v1/arena"
        self.credentials_path = os.path.expanduser("~/.config/mosstrade/credentials.json")
        self.api_key = self._load_or_register()
    
    def _load_or_register(self):
Confidence
98% confidence
Finding
The sample code automatically reads and writes the API key to `~/.config/mosstrade/credentials.json` without any permission hardening or secret-store integration. This normalizes insecure secret handling in executable examples and makes credential theft easier on multi-user systems, compromised hosts, or through backup/logging leakage.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The documentation explicitly says position closing should use `reduce_only: true`, but `close_position()` calls `_place_order()` without setting it. In a one-way position model, a close request larger than the current position or a timing/state mismatch can open a new opposite-direction position, causing unintended leveraged exposure and losses.

Missing User Warnings

High
Confidence
96% confidence
Finding
The skill presents natural-language strategy setup as if the agent will execute leveraged trading automatically, but it does not provide strong warnings, confirmations, or risk disclosures at the point of enabling automation. In this context, the skill controls simulated but realistic trading flows, so understated warnings can normalize autonomous high-risk actions and lead to unsafe user expectations or accidental execution if later integrated.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The activation condition is overly broad: mentions of '模拟交易', 'MossTrade', or '交易机器人' can trigger a skill capable of placing leveraged trades. In an agent environment, ambiguous activation increases the chance of invoking account-linked trading functions when the user only wanted discussion, analysis, or unrelated help.

External Transmission

Medium
Category
Data Exfiltration
Content
首次使用需要注册,获取 API Key:

```bash
curl -X POST https://lark.openclaw-ai.cc/api/v1/arena/enroll \
  -H "Content-Type: application/json" \
  -d '{
    "name": "你的Bot名称",
Confidence
86% confidence
Finding
The skill instructs the agent/user to send registration data to an external domain and obtain a bearer credential from that service. External transmission is expected for an API-backed trading skill, but it still creates security risk because identifiers and future account operations depend on a third-party endpoint outside the local trust boundary.

External Transmission

Medium
Category
Data Exfiltration
Content
### 获取市场价格

```bash
curl "https://lark.openclaw-ai.cc/api/v1/arena/market/snapshot?symbol=BTC-USDT" \
  -H "Authorization: Bearer arena_sk_xxx"
```
Confidence
84% confidence
Finding
This call sends an authorization bearer token to an external service to retrieve market data. Although necessary for the skill's function, transmitting credentials to a remote endpoint expands exposure if the endpoint is compromised, logs headers, or is mistakenly invoked in the wrong context.

External Transmission

Medium
Category
Data Exfiltration
Content
### 查看持仓

```bash
curl https://lark.openclaw-ai.cc/api/v1/arena/portfolio \
  -H "Authorization: Bearer arena_sk_xxx"
```
Confidence
84% confidence
Finding
The portfolio request transmits a bearer token to a third-party service and retrieves sensitive financial state data. In a skill that manages trading accounts, this is more sensitive than ordinary API usage because the returned holdings and balances could inform follow-on abuse if exposed.

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The prose says a user can describe a strategy in natural language, that the agent will save it, and that the strategy is 'already active', including a stated save path `~/.config/mosstrade/strategy.md`. But the only code example in the file implements direct API calls for registration, status, price, portfolio, and order placement; it does not read, write, or execute any strategy file.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
L573-L585 的自然语言交互说明和示例完全以中文呈现,并默认 Agent 以中文理解和回复策略设置,但未说明是否支持其他语言或允许用户选择语言。这可能构成语言/locale 偏好被隐式固定的情况。

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:407