Back to skill

Security audit

XT Exchange

Security checks for vulnerabilities and agentic risk

Overview

This XT.COM trading skill matches its stated purpose, but it handles live financial actions and credentials in ways users should review carefully before installing.

Review this as a high-risk financial automation skill. Use API keys with the minimum permissions needed, disable withdrawal permission unless required, prefer environment or platform-managed secrets over a plaintext credentials file, do not let the agent print credential values, and avoid using XT_HOST or XT_FUTURES_HOST with authenticated commands unless you fully trust the destination.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:47
Finding
Credential values are exposed through diagnostic commands<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 47–50 **Vulnerability Type**: Credential disclosure through command output **Risk Level**: High ### Vulnerable Code ```bash # Check environment variables echo $XT_ACCESS_KEY # Or check the local file cat ~/.xt-exchange/credentials.json 2>/dev/null ``` ### Technical Analysis The documented credential checks print sensitive authentication material rather than merely checking whether it exists. The first command exposes the XT.COM access key, while the second can expose the complete credential file, including both the access key and secret key. When an AI agent executes these commands, their output may be retained in the agent transcript, terminal logs, debugging records, observability systems, or chat history. Credential presence can be verified without reading or displaying the values. Access to `~/.xt-exchange/credentials.json` is otherwise consistent with authenticated exchange functionality. The vulnerability is specifically the instruction to print its contents, which exceeds the minimum access necessary for checking credential availability. ### Attack Path 1. A user requests an authenticated account or trading operation. 2. The agent follows the Skill instructions and checks credential availability. 3. The agent executes `echo $XT_ACCESS_KEY` or `cat ~/.xt-exchange/credentials.json`. 4. The access key or complete credential pair appears in command output. 5. The output is captured in an agent transcript, terminal log, or monitoring system. 6. A party with access to those records obtains the credentials. 7. The exposed credentials are used against XT.COM within the API key's configured permissions. ### Impact Assessment Exposure of both the access key and secret key may allow an attacker to generate authenticated XT.COM requests. Depending on the API key permissions and exchange-side restrictions, this may expose account balances and order history or permit order placement, c ...[truncated 224 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace value-disclosing commands with tests that reveal only whether credentials are available: ```bash if test -n "$XT_ACCESS_KEY" && test -n "$XT_SECRET_KEY"; then echo "Environment credentials are configured." fi if test -r "$HOME/.xt-exchange/credentials.json"; then echo "A readable credential file is present." fi ``` Additional hardening measures: 1. Explicitly instruct the agent never to print, quote, summarize, or paste credential values. 2. Require restrictive credential-file permissions, such as mode `0600`. 3. Validate the credential file structurally inside the Python scripts without returning its contents. 4. Redact known credential fields from logs and agent tool output. 5. Recommend API keys with only the permissions necessary for intended operations. 6. Recommend IP allowlisting and disabling withdrawal permissions unless withdrawals are explicitly required. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/xt_spot.py:52
Finding
Spot API credentials can be redirected to an environment-controlled host<![CDATA[ ## Vulnerability Details **File Location**: `scripts/xt_spot.py`, lines 52–107 **Vulnerability Type**: Unvalidated authenticated endpoint override **Risk Level**: High ### Vulnerable Code ```python DEFAULT_HOST = "https://sapi.xt.com" class XtSpot: def __init__(self, host=None, access_key=None, secret_key=None): self.host = host or os.environ.get("XT_HOST", DEFAULT_HOST) if access_key and secret_key: self.access_key, self.secret_key = access_key, secret_key else: self.access_key, self.secret_key = load_credentials() self.anonymous = not (self.access_key and self.secret_key) self.timeout = 10 self.headers = { "Content-type": "application/json", "User-Agent": "xt-spot-cli/1.0", } def _req(self, url, method="GET", params=None, body=None, auth=True): if auth and self.anonymous: raise RuntimeError( f"需要 API Key。请创建凭证文件 {CREDENTIALS_FILE}," "或设置环境变量 XT_ACCESS_KEY 和 XT_SECRET_KEY" ) full_url = self.host + url if auth: headers = self._auth_headers(url, method, params=params, body=body) else: headers = self.headers kwargs = {"headers": headers, "timeout": self.timeout} if params: kwargs["params"] = params if body: kwargs["json"] = body resp = requests.request(method, full_url, **kwargs) ``` ### Technical Analysis The `XT_HOST` environment variable controls the destination of all spot API requests without validating the scheme, hostname, port, or origin. Authenticated requests subsequently attach the access key and HMAC signature before sending the request to that destination. An attacker who can influence the process environment does not need to recover the secret key from memory. Redirecting a request to an attacker-controlled HTTPS endpoint exposes the access key, signed r ...[truncated 1676 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Remove the host override in production and use the fixed XT.COM origin: ```python DEFAULT_HOST = "https://sapi.xt.com" class XtSpot: def __init__(self, access_key=None, secret_key=None): self.host = DEFAULT_HOST ``` If an override is required for testing: 1. Parse the URL with `urllib.parse.urlsplit`. 2. Require HTTPS. 3. Reject user information, fragments, unexpected ports, and non-allowlisted hostnames. 4. Permit authenticated requests only when the normalized origin exactly matches an approved XT.COM origin. 5. Refuse to load or attach credentials when a development or non-production endpoint is selected. 6. Keep test endpoint support behind an explicit development flag that is disabled by default. 7. Add tests proving that credentials cannot be sent to arbitrary hosts, subdomains, lookalike domains, or URLs containing user-info tricks. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/xt_futures.py:56
Finding
Futures API credentials can be redirected to an environment-controlled host<![CDATA[ ## Vulnerability Details **File Location**: `scripts/xt_futures.py`, lines 56–103 **Vulnerability Type**: Unvalidated authenticated endpoint override **Risk Level**: High ### Vulnerable Code ```python DEFAULT_HOST = "https://fapi.xt.com" class XtFutures: def __init__(self, host=None, access_key=None, secret_key=None): self.host = host or os.environ.get("XT_FUTURES_HOST", DEFAULT_HOST) if access_key and secret_key: self.access_key, self.secret_key = access_key, secret_key else: self.access_key, self.secret_key = load_credentials() self.anonymous = not (self.access_key and self.secret_key) self.timeout = 10 def _req(self, path, method="GET", params=None, auth=True): if auth and self.anonymous: raise RuntimeError( f"需要 API Key。请创建凭证文件 {CREDENTIALS_FILE}," "或设置环境变量 XT_ACCESS_KEY 和 XT_SECRET_KEY" ) full_url = self.host + path if auth: headers = self._auth_headers(path, params) if method == "GET": resp = requests.get( full_url, params=params, headers=headers, timeout=self.timeout ) else: resp = requests.post( full_url, params=params, headers=headers, timeout=self.timeout ) ``` ### Technical Analysis The `XT_FUTURES_HOST` environment variable is accepted as the base URL for authenticated futures requests without origin validation. The client loads real credentials, creates authentication headers, and sends them to the selected host. This makes environment integrity part of the credential trust boundary. A poisoned process environment can redirect account, position, order, and trade requests to a server controlled by an attacker. Although the s ...[truncated 1590 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Use a fixed production endpoint for authenticated futures operations: ```python DEFAULT_HOST = "https://fapi.xt.com" class XtFutures: def __init__(self, access_key=None, secret_key=None): self.host = DEFAULT_HOST ``` If endpoint configurability must remain: 1. Normalize and parse the URL before use. 2. Require an exact allowlisted HTTPS origin. 3. Reject unexpected ports, user information, redirects, and lookalike domains. 4. Do not attach authentication headers when the destination is not the approved production origin. 5. Separate anonymous testing clients from authenticated production clients. 6. Disable environment-based host overrides by default. 7. Add automated tests confirming that attacker-controlled host values cannot receive credential-bearing requests. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:61
Finding
Python dependency is installed without version or integrity pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 61–65 **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash pip3 install requests -q ``` ### Technical Analysis The installation instruction resolves the latest available `requests` package from whatever package index and pip configuration are active in the environment. It does not pin a reviewed version, verify artifact hashes, or use a locked dependency set. The package name itself is legitimate, and the reviewed project does not demonstrate dependency confusion or typosquatting. The security issue is the uncontrolled and mutable dependency resolution process. A compromised package index, altered pip configuration, malicious mirror, or future compromised release could cause unreviewed code to be installed. Python package installation can execute build-system or installation-related code with the privileges of the user running pip. The installed package is later imported by scripts that process exchange credentials and authenticated financial requests. ### Attack Path 1. The agent follows the first-use dependency installation instruction. 2. `pip3` uses the environment's configured package index, mirrors, and resolution settings. 3. A compromised index, malicious mirror, altered configuration, or compromised package release supplies an unreviewed artifact. 4. Pip installs the artifact under the invoking user's privileges. 5. The spot or futures script imports `requests`. 6. Malicious dependency code can access process environment variables, local files available to the user, and authenticated exchange traffic. ### Impact Assessment A malicious installed dependency could execute with the user's local privileges. It could read `XT_ACCESS_KEY`, `XT_SECRET_KEY`, and `~/.xt-exchange/credentials.json`; alter or observe exchange requests; tamper with order parameters; or access other files available to the user. The iss ...[truncated 176 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Use a reviewed, pinned dependency file with cryptographic hashes. For example: ```text # requirements.txt requests==<reviewed-version> --hash=sha256:<verified-artifact-hash> ``` Install it through the intended interpreter: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` Additional controls: 1. Commit the lock or requirements file to the project. 2. Pin all transitive dependencies where the selected packaging workflow requires it. 3. Obtain hashes from reviewed artifacts and update them through a controlled process. 4. Use a trusted, explicitly configured package index. 5. Prefer a virtual environment rather than modifying the global Python installation. 6. Run dependency vulnerability and provenance checks during release preparation. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (27)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This mismatch specifically includes undeclared credential and file access, which is more serious than a simple documentation error. Claiming one scope while reading API keys from environment variables or ~/.xt-exchange/credentials.json can cause secrets exposure and authenticated account actions under false assumptions about what the skill does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
This mismatch specifically includes undeclared credential and file access, which is more serious than a simple documentation error. Claiming one scope while reading API keys from environment variables or ~/.xt-exchange/credentials.json can cause secrets exposure and authenticated account actions under false assumptions about what the skill does.

Credential Access

High
Category
Privilege Escalation
Content
脚本优先读取以下凭证(按优先级):

1. **环境变量**(推荐):`XT_ACCESS_KEY` + `XT_SECRET_KEY`
2. **本地文件**:`~/.xt-exchange/credentials.json`

在执行需要认证的操作前,先检查凭证是否存在:
Confidence
95% confidence
Finding
The skill instructs the agent to obtain exchange API credentials from environment variables or a local credentials file. In a financial skill, credential access is highly sensitive because those keys may authorize balance queries, trading, transfers, or withdrawals; reading them without tightly scoped permissions and consent materially increases account-compromise risk.

Credential Access

High
Category
Privilege Escalation
Content
echo $XT_ACCESS_KEY

# 或检查本地文件
cat ~/.xt-exchange/credentials.json 2>/dev/null
```

若两者均未设置,引导用户:
Confidence
98% confidence
Finding
The command `cat ~/.xt-exchange/credentials.json` explicitly reads a local secret file, which can expose API credentials to the agent runtime, logs, or downstream tools. In context, this is especially dangerous because the same skill also supports irreversible financial operations, so stolen or mishandled credentials could directly lead to account abuse.

Credential Access

High
Category
Privilege Escalation
Content
若两者均未设置,引导用户:

> 「需要 API Key 才能进行账户操作。请在 XT.COM 的 API 管理页面创建 Key,设置环境变量 XT_ACCESS_KEY 和 XT_SECRET_KEY,或将其保存到 ~/.xt-exchange/credentials.json。」

## 安装 Python 依赖
Confidence
91% confidence
Finding
Prompting users to store API keys in ~/.xt-exchange/credentials.json encourages persistence of high-value exchange secrets in a predictable local file path. While common in CLI tooling, this pattern is risky in an agent context because other skills, tools, or misconfigurations may access that file and use the credentials for authenticated trading or withdrawals.

Missing User Warnings

High
Confidence
98% confidence
Finding
The CLI exposes live futures trading and cancellation actions that immediately submit authenticated orders to the exchange with no confirmation prompt, dry-run mode, or explicit acknowledgement. In an agent skill context, this materially increases the chance of accidental or prompt-induced execution of real financial transactions, potentially causing direct monetary loss.

Credential Access

High
Category
Privilege Escalation
Content
"""
XT.COM 现货交易 CLI
Base URL: https://sapi.xt.com (可由 XT_HOST 环境变量覆盖)
认证优先级:构造参数 > 环境变量(XT_ACCESS_KEY/XT_SECRET_KEY) > ~/.xt-exchange/credentials.json
"""
import argparse
import hashlib
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""
XT.COM 现货交易 CLI
Base URL: https://sapi.xt.com (可由 XT_HOST 环境变量覆盖)
认证优先级:构造参数 > 环境变量(XT_ACCESS_KEY/XT_SECRET_KEY) > ~/.xt-exchange/credentials.json
"""
import argparse
import hashlib
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""
XT.COM 现货交易 CLI
Base URL: https://sapi.xt.com (可由 XT_HOST 环境变量覆盖)
认证优先级:构造参数 > 环境变量(XT_ACCESS_KEY/XT_SECRET_KEY) > ~/.xt-exchange/credentials.json
"""
import argparse
import hashlib
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""
XT.COM 现货交易 CLI
Base URL: https://sapi.xt.com (可由 XT_HOST 环境变量覆盖)
认证优先级:构造参数 > 环境变量(XT_ACCESS_KEY/XT_SECRET_KEY) > ~/.xt-exchange/credentials.json
"""
import argparse
import hashlib
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

High
Confidence
96% confidence
Finding
The buy and sell commands place live orders immediately without disclosing that they will execute real trades or asking for confirmation. In an autonomous agent skill, this is dangerous because malformed inputs, manipulated conversation context, or user misunderstanding can cause unintended market or limit orders and direct financial loss.

Missing User Warnings

High
Confidence
97% confidence
Finding
The withdraw command submits a real withdrawal request immediately with user-supplied destination address and amount, but provides no interactive warning, dry-run, or confirmation step. In an agent-driven or conversational setting, a mistaken parse, prompt injection, or ambiguous user instruction could directly trigger irreversible asset loss to an attacker-controlled address.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill declares no explicit tool scope or permissions despite instructing access to environment variables, local credential files, package installation, and network-capable trading scripts. Missing scoping increases the chance an agent executes broader capabilities than users expect, especially in a financial-trading context where secrets and irreversible actions are involved.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The skill content is written as an instruction to operate in Chinese and specifies the invocation flow in Chinese text, without offering the user a language choice. This creates a locale/language policy issue because the skill appears to enforce a specific language by default rather than asking or allowing opt-in.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The request helper sends signed authenticated HTTP requests for balances, positions, orders, and trade actions to a remote exchange API, which necessarily transmits account identifiers and trading data over the network. While networking is part of the tool's purpose, the file lacks a visible user-facing warning or description that authenticated commands will send account and order information to XT.COM.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# ── 公开接口 ──
    def ticker(self, symbol):
        return self._req("/future/market/v1/public/q/ticker", params={"symbol": symbol}, auth=False)

    def depth(self, symbol, limit=20):
        return self._req("/future/market/v1/public/q/depth", params={"symbol": symbol, "level": limit}, auth=False)
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The bulk cancel command cancels open orders immediately and gives no prior disclosure or confirmation. While less severe than withdrawal, this can still disrupt active strategies, cause missed fills, or interfere with legitimate trading activity if invoked accidentally or via adversarial instruction injection.

Static analysis

No suspicious patterns detected.