Back to skill

Security audit

Grid Trading

Security checks for vulnerabilities and agentic risk

Overview

This is a real automated on-chain trading skill, but it has under-disclosed notification, credential-discovery, and transaction-signing risks that users should review carefully before installing.

Install only after reviewing the live-trading behavior, using a low-balance dedicated wallet and least-privilege OKX credentials, disabling or removing Telegram auto-discovery unless explicitly wanted, avoiding the cron command that sources .env, and verifying transaction validation, approval limits, stop/resume behavior, and the effective configuration before allowing unattended trading.

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

T09 · Insecure Skill Coding Practices

Error
Location
references/eth_grid.py:922
Finding

Unvalidated Remote Transaction Data Is Signed and Broadcast

Content
View full analysis
tuple[str | None, dict | None]: """Execute swap via onchainos CLI + Agentic Wallet (TEE signing).""" if direction == "SELL": from_token, to_token = ETH_ADDR, USDC_ADDR else: from_token, to_token = USDC_ADDR, ETH_ADDR for attempt in range(2): quote_time = time.time() swap_data = onchainos_cmd( [ "swap", "swap", "--from", from_token, "--to", to_token, "--amount", str(amount), "--chain", chain, "--wallet", WALLET_ADDR, "--slippage", str(SLIPPAGE_PCT), ] ) if not swap_data or not swap_data.get("ok") or not swap_data.get("data"): detail = json.dumps(swap_data)[:200] if swap_data else "no response" log(f"Swap quote failed (attempt {attempt + 1}): {detail}") if attempt == 0: time.sleep(3) continue return None, { "reason": "swap_quote_failed", "detail": detail, "retriable": True, "hint": "transient_api_error", } tx = swap_data["data"][0]["tx"] log( f" OKX swap: to={tx['to'][:10]}... value={tx.get('value', '0')} " f"gas={tx.get('gas', 'N/A')} gasPrice={tx.get('gasPrice', 'N/A')}" ) sim_result = simulate_tx(tx) if direction == "BUY": router_addr = tx["to"] if not ensure_approval(router_addr, amount): ...[truncated 3704 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
references/eth_grid.py:776
Finding

Unlimited USDC Approval Is Created from Unverified Calldata

Content
View full analysis
bool: """Ensure USDC approval for spender via onchainos.""" state = load_state() approved_routers = state.get("approved_routers", []) if spender.lower() in [r.lower() for r in approved_routers]: return True log(f"USDC approval needed for {spender[:10]}... Approving...") max_approval = ( "115792089237316195423570985008687907853269984665640564039457584007913129639935" ) data = onchainos_cmd( [ "swap", "approve", "--token", USDC_ADDR, "--amount", max_approval, "--chain", "base", ] ) if not data or not data.get("ok") or not data.get("data"): log(f"Approve API failed: {json.dumps(data)[:200] if data else 'no response'}") return False approve_tx = data["data"][0] approve_tx["to"] = USDC_ADDR tx_hash, fail = _wallet_contract_call(approve_tx) if not tx_hash: log(f"Approval failed: {fail}") return False log(f"Approval TX: {tx_hash}") time.sleep(5) approved_routers.append(spender) state["approved_routers"] = approved_routers save_state(state) log(f"Router {spender[:10]}... added to approved list") return True ``` ### Technical Analysis The function accepts a specific `spender` and trade `amount`, but it does not bind either value to the transaction that is signed. Instead, it requests an approval for the maximum possible `uint256` value: ```text 2^256 - 1 ``` The approval command does not explicitly receive the expected `spender`. The code then trusts the returned calldata without decoding it to confirm that: - The function is `approve(address,uint25 ...[truncated 1771 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
references/eth_grid.py:1135
Finding

Undeclared Telegram Credential Discovery Causes Automatic Financial Data Disclosure

Content
View full analysis
tuple[str, str]: """Return (bot_token, chat_id). Checks env first, then zeroclaw config.""" token = os.environ.get("TELEGRAM_BOT_TOKEN", "") chat_id = os.environ.get("TELEGRAM_CHAT_ID", "") if token and chat_id: return token, chat_id # Try zeroclaw-strategy config for cfg_dir in ["zeroclaw-strategy", "zeroclaw", "openclaw"]: cfg_path = Path.home() / f".{cfg_dir}" / "config.toml" if cfg_path.exists(): try: text = cfg_path.read_text() # Simple TOML parse for telegram section in_tg = False for line in text.splitlines(): stripped = line.strip() if stripped.startswith("[") and "telegram" in stripped.lower(): in_tg = True continue if stripped.startswith("[") and in_tg: break if in_tg and "=" in stripped: k, v = stripped.split("=", 1) k, v = k.strip(), v.strip().strip('"').strip("'") if k == "bot_token" and not token: token = v if k == "chat_id" and not chat_id: chat_id = v except Exception: pass return token, chat_id ``` It automatically sends messages through the Telegram Bot API: ```python def _send_telegram(text: str) -> bool: """Send a message via Telegram Bot API.""" import urllib.request import urllib.error if not TELEG ...[truncated 3474 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/eth_grid.py:113
Finding

Executable Risk Controls Conflict with Documented and Configured Values

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
README.md:90
Finding

Scheduled Command Executes the Environment File as Shell Code

Content
View full analysis
Remediation
View remediation
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
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (23)

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

Critical
Category
Data Flow
Confidence
93% confidence
Finding

The code reads Telegram bot credentials and chat IDs from environment variables and local config files, then transmits message content to Telegram over the network. In this skill, notifications can include portfolio value, balances, prices, trade outcomes, and failure details, creating an undocumented exfiltration channel beyond the stated Discord-only behavior.

Content

Scanner excerpt · references/eth_grid.py (reported line 1246)May include surrounding context.

python
headers={"Content-Type": "application/json"},
    )
    try:
        urllib.request.urlopen(req, timeout=10)
        return True
    except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError) as e:
        log(f"Telegram send error: {e}")

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

This Discord request also uses credentials loaded from environment or local config and sends operational data to an external service. Unlike Telegram, Discord is disclosed in the skill description, so this is less suspicious, but it still transmits potentially sensitive trading and wallet telemetry that should be explicitly consented to and minimized.

Content

Scanner excerpt · references/eth_grid.py (reported line 1275)May include surrounding context.

python
},
        )
        try:
            urllib.request.urlopen(req, timeout=10)
            discord_ok = True
        except (urllib.error.HTTPError, urllib.error.URLError, TimeoutError) as e:
            log(f"Discord embed error: {e}")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
# 2. 配置
cd ~/.openclaw/skills/grid-trading/references
cp ../.env.example .env    # 填入 API keys + 钱包地址
vi config.json             # 调整网格参数

# 3. 测试(只读,安全)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
# 2. 配置
cd ~/.openclaw/skills/grid-trading/references
cp ../.env.example .env    # 填入 API keys + 钱包地址
vi config.json             # 调整网格参数

# 3. 测试(只读,安全)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
entrypoint: references/eth_grid.py

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill explicitly loads secrets from a local .env file, including exchange credentials and possibly wallet-related configuration. In isolation this is common, but in an agent skill context it is sensitive because the code combines secret loading with trading, network notifications, subprocess execution, and config scavenging, increasing the chance of misuse or unintended disclosure.

Content

Scanner excerpt · references/eth_grid.py (reported line 25)May include surrounding context.

python
from datetime import datetime, timezone, timedelta
from pathlib import Path

# ── Load .env if present ────────────────────────────────────────────────────


def _load_env():

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

The code searches both the script directory and its parent for a .env file and imports any key-value pairs it finds. In a shared or agent-managed workspace, this can ingest unrelated secrets from adjacent directories, violating least privilege and enabling the skill to access more credentials than users expect.

Content

Scanner excerpt · references/eth_grid.py (reported line 31)May include surrounding context.

python
def _load_env():
    # Check script dir first, then parent (skill root for openclaw installs)
    for base in [Path(__file__).parent, Path(__file__).parent.parent]:
        env_file = base / ".env"
        if env_file.exists():
            for line in env_file.read_text().splitlines():
                line = line.strip()

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
89% confidence
Finding

Copying the full process environment into subprocesses exposes all ambient secrets to the onchainos CLI and any child process behavior it may trigger. In a skill environment, this breaks least privilege and can unintentionally disclose unrelated API keys, tokens, or infrastructure credentials to external tools or logs.

Content

Scanner excerpt · references/eth_grid.py (reported line 220)May include surrounding context.

python
def onchainos_cmd(args: list[str], timeout: int = 30) -> dict | None:
    """Run onchainos CLI command, return parsed JSON."""
    env = os.environ.copy()
    env.setdefault("OKX_API_KEY", OKX_API_KEY)
    env.setdefault("OKX_SECRET_KEY", OKX_SECRET)
    env.setdefault("OKX_PASSPHRASE", OKX_PASSPHRASE)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · references/eth_grid.py (reported line 2775)May include surrounding context.

python
def reset():
    """Reset state (recalibrate grid from scratch)."""
    price = get_eth_price()
    eth_bal, usdc_bal = get_balances()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README instructs users to schedule automated live trading on a cron job against on-chain DEX infrastructure, but it does not prominently warn that this can move real funds, incur slippage/gas costs, and execute repeatedly without further confirmation. In a trading bot skill, this omission materially increases the chance of accidental financial loss from misconfiguration or unattended operation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares broad operational capabilities through its design and dependencies, including environment-secret access, file state/log writes, networked API calls, and shell/CLI execution, but does not bound them with an explicit tool scope such as permissions or allowed-tools. In a trading skill that can sign and broadcast on-chain transactions, this omission materially increases the blast radius of prompt mistakes or malicious modifications because an agent may invoke more tools or access more resources than the user expects.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill requires API credentials and a wallet address and is explicitly designed to execute swaps on-chain, yet it does not present a clear warning about secret handling, irreversible trading actions, approval risk, or potential fund loss. In this context, missing user-facing safety disclosures is dangerous because operators may supply live credentials and permit real trades without understanding that the skill can approve spenders, sign transactions, and move assets.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · references/eth_grid.py (reported line 64)May include surrounding context.

python
if env_addr:
        return env_addr
    try:
        result = subprocess.run(
            ["onchainos", "wallet", "addresses"],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · references/eth_grid.py (reported line 88)May include surrounding context.

python
_account_id = os.environ.get("ONCHAINOS_ACCOUNT_ID", "")
if _account_id:
    try:
        _sw = subprocess.run(
            ["onchainos", "wallet", "switch", _account_id],
            capture_output=True,
            text=True,

Tainted flow: '_account_id' from os.environ.get (line 85, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · references/eth_grid.py (reported line 88)May include surrounding context.

python
_account_id = os.environ.get("ONCHAINOS_ACCOUNT_ID", "")
if _account_id:
    try:
        _sw = subprocess.run(
            ["onchainos", "wallet", "switch", _account_id],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
81% confidence
Finding

This generic wrapper executes many externally influenced onchainos subcommands, including values derived from environment variables, API responses, wallet state, and runtime logic. While it avoids shell injection, it is still a dangerous execution primitive in a trading skill because it can trigger wallet operations, approvals, swaps, and network actions with broad authority if upstream inputs are wrong or malicious.

Content

Scanner excerpt · references/eth_grid.py (reported line 225)May include surrounding context.

python
env.setdefault("OKX_SECRET_KEY", OKX_SECRET)
    env.setdefault("OKX_PASSPHRASE", OKX_PASSPHRASE)
    try:
        result = subprocess.run(
            ["onchainos"] + args,
            capture_output=True,
            text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code searches multiple home-directory config locations for Discord and Telegram tokens unrelated to the core trading function. This broad credential harvesting behavior violates least privilege and increases the blast radius if the skill is run in an environment containing personal or cross-application messaging secrets.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill description says Discord notification, but the code also implements Telegram messaging and auto-discovers Telegram credentials from environment variables and local config files. That mismatch materially changes the data-exposure surface and is especially dangerous in a wallet-connected trading bot where silent extra channels can leak sensitive operational information.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

This is a real external transmission endpoint to Telegram. In the context of an automated trading bot with wallet integration, sending notifications off-platform can expose financial activity, balances, stop conditions, and operational errors to third parties if enabled without explicit user awareness.

Content

Scanner excerpt · references/eth_grid.py (reported line 1233)May include surrounding context.

python
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
        return False
    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
    payload = {
        "chat_id": TELEGRAM_CHAT_ID,
        "text": text,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This Python skill contains numerous user-facing strings and notifications in Chinese, such as deposit detection messages here and throughout status/report/alert paths, without offering a language selection or documenting that the skill is intentionally limited to a Chinese-speaking context. That creates a natural-language policy issue because the skill imposes a specific language on users rather than allowing opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README content, commands table descriptions, and operational guidance are presented only in Chinese. This creates a language/locale policy concern because the skill appears to force a single language without explicit opt-in or justification for a region-specific audience.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation tells users to copy .env.example to .env and populate API keys and wallet addresses, but it does not include guidance on secret handling, file permissions, or avoiding accidental disclosure. While this is common setup guidance, omitting even basic security warnings can lead to credential leakage through backups, shell history, screenshots, or source control.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The operational interface specifies that the report command generates a daily performance report in Chinese, but there is no indication that the user can choose another language or opt in to this locale constraint. This is a natural-language policy issue because it imposes a specific language by default.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.