Back to skill

Security audit

OKX Trading with Permission Gate

Security checks for vulnerabilities and agentic risk

Overview

This OKX trading skill is purpose-built for crypto trading, but it needs Review because its approval and guardrail design may not reliably prevent unintended live orders.

Install only if you are comfortable reviewing and operating a high-impact trading automation skill. Use demo mode first, prefer tightly scoped OKX keys with no withdrawal permission and IP restrictions, set small per-trade and daily caps, avoid live grid autonomy until the confirmation-token, guardrail recheck, and concurrency issues are fixed, and pin reviewed dependency versions before use.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_pending.py:64
Finding

Local Confirmation Token Does Not Prove Human Approval

Content
View full analysis
tuple[str, str]: """Create a new pending record. Returns (id, confirmation_token).""" _ensure_dirs() if ttl_seconds is None: ttl_seconds = TRADE_TTL_SECONDS if kind == "trade" else GRID_TTL_SECONDS pid = new_id() token = _new_token() record = { "id": pid, "confirmation_token": token, "kind": kind, "payload": payload, "created_at": now_iso(), "expires_at_epoch": int(time.time()) + ttl_seconds, } path = _path(pid) path.write_text(json.dumps(record, indent=2)) os.chmod(path, 0o600) return pid, token ``` The trade execution path then accepts possession of that token as authorization: ```python try: record = load_pending(args.id) validate_token(record, args.confirmation_token) except PendingError as e: print(f"REFUSED: {e}", file=sys.stderr) return 3 if record.get("kind") != "trade": print(f"REFUSED: proposal {args.id} is kind={record.get('kind')!r}, not 'trade'", file=sys.stderr) return 3 payload = record["payload"] api_params = payload["api_params"] try: check_all(payload["instId"], float(payload["notional_usdt"])) except GuardrailError as e: print(f"REFUSED at execute time: {e}", file=sys.stderr) return 3 resp = trade_api().place_order(**api_params) ``` ### Technical Analysis The confirmation token proves only that the caller can read the local pending file. It does not prove that the user sent the documented `YES ` response. The Skill instructions explicitly direct the Agent to read that same pending file to obtain the token. Consequently, the proposing ...[truncated 1465 chars]
Remediation
View remediation
` from the correct user and conversation. 3. Bind approval to: - Proposal ID - Authenticated user and account - Conversation or session ID - Immutable hash of the complete order payload - Creation and expiration timestamps 4. Have execution atomically consume server-side approval state rather than accepting a bearer token readable by the Agent. 5. Prevent the proposal process from writing or reading approval credentials. 6. Preserve single-use and expiry protections, but treat them as replay defenses rather than proof of human consent. 7. Log the authenticated approval event and consumed payload hash for later audit. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/okx_grid_apply.py:38
Finding

Grid Application Does Not Revalidate Financial Guardrails

Content
View full analysis
= payload["ref_price_at_propose"]: # Sells deferred until matching buys fill — recorded as pending levels. continue # Spot limit buy: sz is base currency. base_sz = quote_sz / level_px sz_str = f"{base_sz:.8f}".rstrip("0").rstrip(".") px_str = f"{level_px:.8f}".rstrip("0").rstrip(".") resp = api.place_order( instId=inst_id, tdMode="cash", side="buy", ordType="limit", sz=sz_str, px=px_str, ) ``` ### Technical Analysis Grid proposals remain valid for up to 30 minutes. During that period, other trades or grid fills may consume daily capacity, and the symbol allowlist or configured limits may change. The earlier check therefore cannot safely authorize later execution. Unlike `okx_execute_trade.py`, `okx_grid_apply.py` does not perform execute-time validation. This creates a time-of-check/time-of-use gap and contradicts the stated policy that guardrails are rechecked before irreversible actions. The application also places multiple orders sequentially without reserving aggr ...[truncated 850 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/okx_grid_step.py:274
Finding

Autonomous Grid Rescaling Bypasses the Daily Notional Limit

Content
View full analysis
= cur_px: continue if max_position_base > 0 and cur_pos >= max_position_base: audit_append( "position_capped", strategy_id=strategy["id"], level_idx=idx, position=round(cur_pos, 8), cap=max_position_base, context="rescale", ) continue placed = _place_buy(api, inst_id, idx, lvl_px, quote_sz) if placed: replacements.append(placed) ``` `_place_buy` directly submits the replacement order: ```python def _place_buy(api, inst_id: str, level_idx: int, level_px: float, quote_sz: float) -> dict | None: base_sz = quote_sz / level_px resp = api.place_order( instId=inst_id, tdMode="cash", side="buy", ordType="limit", sz=_format_sz(base_sz ...[truncated 1487 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/okx_grid_step.py:144
Finding

Grid Maintenance Is Not Safe Under Concurrent Scheduler Execution

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/_okx_client.py:97
Finding

Trading Credentials Are Unnecessarily Supplied to Public API Clients

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Security-Sensitive Dependencies Are Not Reproducibly Pinned

Content
View full analysis
=0.4.0 numpy>=1.24 ``` ### Technical Analysis Both requirements use lower-bound-only constraints. A future installation may therefore resolve to any later package version, including a release that has not been reviewed with this Skill. This is particularly sensitive for `python-okx`: the package receives the user's API key, secret, and passphrase and can submit financial orders. A compromised upstream release or an incompatible behavioral change would execute with those privileges when the Skill imports the package. The audit did not identify typosquatting or an explicitly malicious package in the current requirements. The issue is the lack of deterministic, reviewed dependency resolution. ### Attack Path 1. A new, compromised, or incompatible dependency release is published after this Skill version was audited. 2. A user runs `pip install -r requirements.txt`. 3. The resolver selects the newer release because it satisfies the `>=` constraint. 4. The Skill imports that release. 5. For `python-okx`, the dependency receives live account credentials and is invoked to query the account or place orders. ### Impact Assessment A supply-chain compromise could expose OKX credentials, manipulate market responses, alter order parameters, or submit unauthorized trades with the permissions granted to the API key. An incompatible update could also disable timeouts or break safety assumptions. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code's actual behavior is limited to retrieving and displaying open orders from OKX. The declared description presents a broader trading skill focused on balances, prices, proposing/executing trades, DCA, grid strategies, and confirmations before execution. While open orders may be adjacent to trading workflows, this specific capability is not explicitly included in the description, and the code does not implement the advertised confirmation gate or strategy functionality. Therefore the supplied code chunk does not accurately represent the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code is a narrow read-only utility for listing open OKX positions, especially for non-spot products such as margin, swaps, futures, and options. The declared description presents a much broader trading skill centered on balances, prices, trade execution with explicit confirmation, DCA/grid strategies, and daily snapshots, with defaults to demo trading and spot instruments. While position inspection could loosely relate to account monitoring, open positions are not explicitly described, and the script’s focus on leveraged/non-spot instrument types materially differs from the stated default spot orientation. There is no trading or confirmation logic in this chunk, so the actual behavior is narrower and somewhat inconsistent with the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents a comprehensive OKX trading skill whose key safety property is that trades are never executed without explicit human confirmation. The actual code chunk is only a daily snapshot/reporting utility. It accesses OKX account, market, and trade-history/order-list endpoints to assemble a portfolio/activity digest, writes it to disk, and prints a summary. That does align with the narrow sub-capability of 'get a daily snapshot/PnL digest,' but it does not represent the broader declared purpose of proposing/executing trades, running DCA or grid strategies, or enforcing a confirmation gate. Because the code’s primary purpose is materially narrower and different from the declared full trading assistant behavior, and it also performs undeclared local persistence, this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 48)May include surrounding context.

pip install -r skills/aeon/okx-trading/requirements.txt

text

2. **Get OKX demo API credentials.** Log in at <https://www.okx.com>, switch to "Demo trading" in the top-right account menu, then go to Account → API. Create a key with **Trade** permission, save the API key, secret, and passphrase. (Live keys go in the same place but on the live account; do NOT mix them.)

3. **Set environment variables** in `.env` (and `source` it before running aeon):

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% 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.

Content

Scanner excerpt · README.md (reported line 86)May include surrounding context.

dca_dip_state.json # drawdown-trigger state (v0.3.0+)

text

Files are 0600 so the confirmation token is not world-readable. Pending proposals expire automatically (10 min for trades, 30 min for grids).

## What the user types in chat

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes shell commands, accesses environment variables containing exchange credentials, reads and writes local files, and relies on networked trading scripts, but it declares no explicit tool scope. In a trading skill, that omission is dangerous because it gives the agent broad implicit authority over high-risk capabilities without a machine-readable restriction boundary, increasing the chance of misuse, prompt-injection pivoting, or accidental execution with live credentials.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill first insists that execution must use the absolute pending-file path printed by the propose step, then later instructs the agent to read a guessed path under ~/.aeon/okx/pending/.json. That contradiction weakens the confirmation control: an agent could read the wrong file, fail open in edge cases, or be steered toward attacker-controlled/incorrect state, undermining the integrity of the trade-approval gate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script presents RSI-based outputs as actionable signals using phrases like 'consider buy' and 'consider sell' without any caution that these are simplistic heuristic indicators, not robust investment advice. In a trading skill, such phrasing can unduly influence users or downstream agent reasoning into executing risky trades based on oversimplified logic.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file explicitly states that after the initial confirmed setup, subsequent fills are handled by another script without further confirmation. That behavior conflicts with the skill description’s blanket promise that it never executes a trade without explicit YES confirmation in chat, creating a trust-boundary violation where users may authorize one setup action but unintentionally grant ongoing autonomous trading.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code autonomously cancels existing orders and places replacement buy orders during grid auto-rescale without any per-action user confirmation or user-visible warning at execution time. Although the broader skill description mentions a human-in-the-loop gate for initial setup, this file implements bounded post-setup trading autonomy, so a misconfigured strategy, market move, or compromised scheduler could trigger real account actions repeatedly without fresh consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script deletes the persisted grid strategy and pending record even if one or more exchange order cancellations fail, creating a dangerous mismatch between local state and real exchange state. In a trading skill, this can leave live orders active while the system believes the grid is stopped, leading to unintended fills, unmanaged exposure, and loss of the ability to safely track or unwind the remaining orders.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This is a real vulnerability because the security model explicitly relies on the confirmation token being inaccessible to the LLM, yet the script prints the exact pending file path containing that token. In a tool-enabled agent environment, the LLM can typically use a file-read capability on that path, recover the token, and bypass the intended human-in-the-loop confirmation barrier. In a crypto-trading skill, that weakens the core control protecting against unauthorized trade execution, making the issue more dangerous than it would be in a non-financial context.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · scripts/okx_snapshot.py (reported line 18)May include surrounding context.

python
Designed as the body of a scheduled morning Telegram digest:

  schedule_create  schedule="0 9 * * *"  task="Run okx_snapshot.py"  notify=true

Defaults the watched instrument list from `OKX_ALLOWED_SYMBOLS` plus active
grid strategies. Override with one or more `--instId` flags. Pass

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency python-okx is specified with a lower bound only, which allows future installs to resolve to different versions over time. This creates a supply-chain risk because a later release could introduce breaking changes or a vulnerable version, and in a trading skill that can access exchange accounts, dependency compromise could affect account data or trade execution logic.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
python-okx>=0.4.0
numpy>=1.24

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The numpy dependency is also unpinned, so builds are not reproducible and may silently pull different versions in different environments. In a financial/trading context, unexpected dependency changes can affect numerical behavior, stability, or expose the environment to known package-level vulnerabilities if an unsafe release is selected.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
python-okx>=0.4.0
numpy>=1.24

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
89% confidence
Finding

The manifest references numpy without pinning to a specific version, while multiple advisories exist across historical numpy releases. Because the actual installed version is unverifiable from this file, you cannot determine whether deployment will avoid affected versions, which is a real supply-chain hygiene weakness even though it does not prove an exploitable vulnerable version is currently in use.

Content

No source excerpt is available for this finding.