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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
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.

Content

Scanner excerpt · SKILL.md (reported line 46)May include surrounding context.

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

建议保存位置: ~/.config/mosstrade/credentials.json

json
{
  "api_key": "arena_sk_xxx",

Credential Access

High
Category
Privilege Escalation
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.

Content

Scanner excerpt · SKILL.md (reported line 406)May include surrounding context.

md
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):

Intent-Code Divergence

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 22)May include surrounding context.

首次使用需要注册,获取 API Key:

bash
curl -X POST https://lark.openclaw-ai.cc/api/v1/arena/enroll \
  -H "Content-Type: application/json" \
  -d '{
    "name": "你的Bot名称",

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 87)May include surrounding context.

获取市场价格

bash
curl "https://lark.openclaw-ai.cc/api/v1/arena/market/snapshot?symbol=BTC-USDT" \
  -H "Authorization: Bearer arena_sk_xxx"

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 200)May include surrounding context.

查看持仓

bash
curl https://lark.openclaw-ai.cc/api/v1/arena/portfolio \
  -H "Authorization: Bearer arena_sk_xxx"

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

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

Content

No source excerpt is available for this finding.

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