Back to skill

Security audit

Cex Trader

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed crypto trading tool, but it handles real exchange credentials and live trading authority with unsafe endpoint and credential-entry practices.

Install only if you are comfortable giving the MCP service and this skill trading authority over the exchange accounts you connect. Use exchange API keys with withdrawals and transfers disabled, IP allowlisting where possible, minimal balances, and explicit manual review before any order, leverage change, cancellation, or position close. Avoid entering secrets through CLI flags, and do not set MCP_SERVER_URL to an untrusted or non-HTTPS remote server.

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

Error
Location
scripts/cex_trader_cli.py:195
Finding

Exchange credentials are exposed through command-line arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/cex_trader_cli.py:151-159, 195-199
Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: High

Vulnerable Code

python
def cmd_setup_save(args):
    params = {
        "exchange": args.exchange,
        "apiKey": args.apiKey,
        "secretKey": args.secretKey,
    }
    if args.passphrase:
        params["passphrase"] = args.passphrase
    print_result(call_tool("cex-setup-save", params))
python
s_save = setup_sub.add_parser("save", help="Save API credentials")
s_save.add_argument("--exchange", required=True, choices=["okx", "binance"])
s_save.add_argument("--apiKey", required=True, help="API Key")
s_save.add_argument("--secretKey", required=True, help="API Secret")
s_save.add_argument("--passphrase", help="Passphrase (required for OKX)")
s_save.set_defaults(func=cmd_setup_save)

Technical Analysis

The setup interface requires exchange API keys, API secrets, and optional OKX passphrases to be supplied directly as command-line arguments. Command-line secrets may be exposed through:

  • Shell history files.
  • Process inspection utilities while the command is running.
  • Terminal session recording.
  • Operating-system audit facilities.
  • CI/CD job logs and automation wrappers.
  • Diagnostic reports that capture process command lines.

The credentials are subsequently placed into a JSON request and sent to the configured MCP server. Although transmitting credentials is part of the declared remote setup workflow, accepting them through command-line flags is not the minimum exposure necessary to implement that workflow.

Attack Path

  1. A user follows the documented setup pattern and runs the CLI with --apiKey, --secretKey, and possibly --passphrase.
  2. The shell records the full command, or another local user or monitoring process observes the process command line.

...[truncated 920 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove or deprecate the --secretKey and --passphrase command-line options.
  • Read secrets through an interactive hidden prompt using getpass.getpass() when running in a terminal.
  • Support protected environment variables or a secret manager for non-interactive automation.
  • If file-based input is necessary, require restrictive permissions and avoid retaining the file after use.
  • Keep non-secret parameters such as the exchange name as ordinary CLI arguments.
  • Ensure request failures, debug output, telemetry, and exception handlers never print credential-bearing payloads.
  • Update all documentation so examples do not place secrets directly in shell commands.
  • Recommend narrowly scoped, trading-only keys with IP allowlisting and no withdrawal or transfer permissions.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cex_trader_cli.py:29
Finding

Sensitive MCP requests can be sent to unvalidated plaintext or attacker-controlled endpoints

Content
View full analysis

Vulnerability Details

File Location: scripts/cex_trader_cli.py:29-43, 151-159
Vulnerability Type: Missing transport and destination validation for sensitive network requests
Risk Level: High

Vulnerable Code

python
MCP_SERVER_URL = os.environ.get("MCP_SERVER_URL", "http://localhost:3000")


def call_tool(tool_name: str, params: dict) -> dict:
    """Call an MCP tool via HTTP POST."""
    url = f"{MCP_SERVER_URL}/tools/{tool_name}"
    data = json.dumps(params).encode("utf-8")
    req = urllib.request.Request(
        url,
        data=data,
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            return json.loads(resp.read().decode())

The sensitive setup payload is constructed as follows:

python
def cmd_setup_save(args):
    params = {
        "exchange": args.exchange,
        "apiKey": args.apiKey,
        "secretKey": args.secretKey,
    }
    if args.passphrase:
        params["passphrase"] = args.passphrase
    print_result(call_tool("cex-setup-save", params))

Technical Analysis

MCP_SERVER_URL is accepted directly from the environment and used without parsing or validation. The client does not enforce HTTPS for non-loopback destinations, restrict the destination host, or require explicit approval when sending credentials to a custom server.

The default value is http://localhost:3000, which is reasonable for a local development server but does not make the general code path safe. If the environment variable is set to a remote HTTP URL, the same request function transmits exchange API keys, passphrases, account information, and live trading instructions without transport encryption.

An attacker-controlled HTTPS endpoint is also dangerous because ordinary certificate validation only authenticates the selected host; it does not est ...[truncated 1957 chars]

Remediation
View remediation

Remediation Suggestions

  • Parse MCP_SERVER_URL with urllib.parse.urlparse() before constructing requests.
  • Require https:// for every non-loopback destination.
  • Permit plaintext HTTP only when the resolved destination is explicitly verified as loopback, such as 127.0.0.1, ::1, or a carefully validated localhost.
  • Reject embedded credentials, malformed URLs, unexpected schemes, fragments, and ambiguous host representations.
  • Use an allowlist containing the documented hosted MCP domain by default.
  • Require explicit interactive confirmation or a dedicated insecure-development flag before connecting to a custom endpoint.
  • Consider certificate or public-key pinning for the hosted service where operationally feasible.
  • Separate credential enrollment from ordinary tool requests and apply stricter endpoint policy to enrollment.
  • Display the normalized destination before transmitting credentials without displaying the credential values.
  • Document the trust boundary clearly: the MCP operator receives trading credentials and must be trusted with their associated authority.
  • Audit the separately hosted backend for credential retention, encryption, access controls, logging, deletion, idempotency, and advertised risk-control enforcement.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Tainted flow: 'req' from os.environ.get (line 36, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The CLI builds its destination from MCP_SERVER_URL, which is taken directly from the environment and then used for outbound HTTP requests. Because the default and likely usage are plain HTTP and there is no allowlist or transport security enforcement, an attacker who can influence the environment or local network path could redirect trading commands and sensitive account data to an untrusted endpoint, enabling credential theft or unauthorized trade execution.

Content

Scanner excerpt · scripts/cex_trader_cli.py (reported line 43)May include surrounding context.

python
method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        body = e.read().decode()

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares environment-based credentials and a remote MCP endpoint, but does not define an explicit tool scope or permission boundary. In a trading skill that can place spot and leveraged futures orders and transmit API keys to a hosted server, missing scope constraints increases the chance of overbroad access, unintended network use, and unsafe invocation in agent runtimes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are extremely broad, including generic terms like 'buy crypto', 'sell crypto', 'trade', 'swap tokens', and exchange names. In an autonomous or semi-autonomous agent environment, this can cause accidental invocation of a high-risk skill that is capable of placing real spot or leveraged futures orders, making the context especially dangerous.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The example file demonstrates live futures trading actions including leveraged long/short opens, market closes, and full position closure without any explicit warning, sandbox/testnet framing, or requirement for user confirmation. In an AI-agent trading skill, copy-pasteable examples can be directly operationalized, increasing the chance of accidental real-money, leveraged execution and financial loss.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The example file demonstrates live trading and order-cancellation tool invocations using realistic parameters, but provides no warning that these actions can place real orders or affect real funds if copied into an agent workflow. In the context of an AI agent trading skill, this increases the risk of accidental execution, especially because the examples look production-ready rather than clearly sandboxed or mocked.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup command accepts API keys and secrets directly as command-line arguments and forwards them over the network. Command-line secrets are commonly exposed via shell history, process listings, audit logs, and orchestration telemetry, so this handling increases the chance of credential disclosure even if the server is legitimate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The generic call_tool function sends command parameters over HTTP for all operations, including order placement, position closing, leverage changes, and account queries. Although the top-level docstring mentions HTTP, there is no user-facing disclosure in command help or runtime output that these actions transmit trading/account data to the MCP server.

Content

No source excerpt is available for this finding.