Back to skill

Security audit

polymarket-copytrading

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real-money copytrading automation tool with disclosed but risky unattended trading behavior, including automatic paper-to-real venue rerouting and confusing sell defaults.

Install only if you are comfortable giving this skill authority to place and possibly sell trades. Prefer paper mode first, set small caps, set COPYTRADING_FORCE_SIMMER_VENUE=true if you do not want sim signals converted to Polymarket orders, avoid unattended cron/nohup live runs until you have reviewed the behavior, and treat WALLET_PRIVATE_KEY as highly sensitive.

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

T09 · Insecure Skill Coding Practices

Error
Location
copytrading_trader.py:714
Finding

Paper-Trading Reactor Signals Can Trigger Real-Money Trades

Content
View full analysis

Vulnerability Details

File Location: copytrading_trader.py:714-735
Vulnerability Type: Paper-to-live trading authorization escalation
Risk Level: High

Vulnerable Code

python
# Venue auto-routing: when the signal targets Simmer (LMSR) but the size
# exceeds the venue's per-trade hard cap, try Polymarket instead so the user
# follows the whale's actual size rather than getting silently capped.
# Respects COPYTRADING_FORCE_SIMMER_VENUE=true and user's explicit polymarket venue.
effective_venue = venue
effective_amount = amount
_rerouted_to_polymarket = False

# Auto-route requires an EXPLICIT sim venue — a defaulted (omitted) venue
# must never escalate to real-USDC polymarket; it stays on sim and gets
# capped by the venue instead (fail-safe).
if (not FORCE_SIMMER_VENUE
        and raw_venue == "sim"
        and amount > SIMMER_VENUE_TRADE_CAP_USD):
    _rerouted_to_polymarket = True
    effective_venue = "polymarket"
    print(
        f"[reactor] {tx_short}... amount {amount:.2f} $SIM > {SIMMER_VENUE_TRADE_CAP_USD:.0f} $SIM cap "
        f"→ routing to polymarket"
    )

The resulting venue is subsequently passed to the trade execution path:

python
result = _attempt_trade(effective_venue, effective_amount, trade_price)

Technical Analysis

Reactor responses are received from the remote Simmer API and supply security-sensitive trade fields, including venue, amount, market_id, side, and action. When such a signal explicitly specifies the simulated sim venue and its amount exceeds the $500 simulated-venue cap, the code automatically changes the execution venue to polymarket.

This crosses a material authorization boundary: a signal denominated for a paper-trading venue is transformed into a real-money Polymarket order. The reroute does not require an explicit per-order confirmation, a dedicated positive opt-in to paper-to-live conversion, or the normal --live authorization gate. Reactor mode is always live, ...[truncated 1847 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove automatic sim-to-polymarket rerouting. Oversized simulated trades should be capped at the simulated venue’s limit or rejected.
  2. Preserve the venue specified by each signal as a strict security boundary rather than treating it as a routing preference.
  3. If cross-venue execution is required, place it behind an explicit opt-in such as --allow-real-venue-reroute; default this option to disabled.
  4. Require both --live and an explicit real-money venue selection before Reactor mode can submit Polymarket orders.
  5. Enforce a local maximum real-money amount independent of remotely supplied signal values and server-side configuration.
  6. Before any paper-to-live conversion, display the destination venue, amount, market, side, and estimated cost and require an interactive confirmation. For unattended operation, require a separately stored policy that explicitly authorizes such conversion.
  7. Add regression tests proving that an explicit sim signal remains on sim, including when its amount exceeds the simulated-venue cap.
  8. Consider cryptographically binding Reactor configurations to the intended venue and rejecting signals whose venue or amount conflicts with that locally approved configuration.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose focuses on copying or mirroring top Polymarket traders' positions, either via polling or real-time event-driven infrastructure. The supplied code does not implement mirroring, trader tracking, signal handling, execution, or polling of top traders. Instead, it performs read-only account status retrieval for the user's own Simmer account by calling portfolio and positions endpoints and printing summaries. This is a materially different primary purpose, so the description does not accurately represent the code chunk.

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
89% confidence
Finding

The skill recommends cron-based persistence that automatically executes live trading every minute. Although the intent is operational reliability rather than malware, this is still dangerous in context because it creates autonomous, recurring financial actions that can continue after crashes/reboots and may be abused or misconfigured without ongoing user awareness.

Content

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

server will stop delivering events | | price_buffer | Fraction added above whale's fill price for your buy order. Default 0.02 (2%). Prevents order failures on thin books after whale clears liquidity. Range 0–0.2. |

Run reactor mode

Recommended: cron with --once — polls for pending signals once and exits. Run on a 1-minute cron for reliable, persistent coverage:

bash
# Linux crontab
*/1 * * * * cd /path/to/skill && python copytrading_trader.py --reactor --once --live

# OpenClaw cron
openclaw cron add --name "reactor-poll" --cron "*/1 * * * *" --tz UTC --session isolated \
  --message "Run: cd /path/to/skill && python3 copytrading_trader.py --reactor --once"

# One-off check
python copytrading_trader.py --reactor --once

Why cron? Reactor signals expire after a short window. A cron ensures your agent checks for signals reliably, even after reboots or process crashes. If your polling process stops, signals expire silently — cron prevents this.

**Advanc

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill explicitly instructs use of environment variables for sensitive material (SIMMER_API_KEY, WALLET_PRIVATE_KEY) and repeated network access to third-party APIs, but it declares no tool scope or permissions boundary. That creates an authorization gap where an agent may expose secrets or perform external actions without an explicit least-privilege contract.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The skill directs the agent/user to send authenticated PATCH requests to an external API that changes account trading limits. External authenticated state-changing requests are security-sensitive because misuse, prompt-triggered execution, or token leakage could increase financial exposure without adequate review.

Content

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

md
> **Reactor mode note:** `cadence_mode` controls polling-mode trade budget only. In Reactor mode, each whale signal is handled individually by `_process_reactor_signal` — the per-run cap doesn't apply. If you hit `Daily trade limit reached (10/day)` in Reactor mode, raise the server-side limit via:
> ```bash
> curl -X PATCH "https://api.simmer.markets/api/sdk/user/settings" \
>   -H "Authorization: Bearer $SIMMER_API_KEY" \
>   -H "Content-Type: application/json" \
>   -d '{"max_trades_per_day": 200}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The skill directs the agent/user to send authenticated PATCH requests to an external API that changes account trading limits. External authenticated state-changing requests are security-sensitive because misuse, prompt-triggered execution, or token leakage could increase financial exposure without adequate review.

Content

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

md
> **Reactor mode note:** `cadence_mode` controls polling-mode trade budget only. In Reactor mode, each whale signal is handled individually by `_process_reactor_signal` — the per-run cap doesn't apply. If you hit `Daily trade limit reached (10/day)` in Reactor mode, raise the server-side limit via:
> ```bash
> curl -X PATCH "https://api.simmer.markets/api/sdk/user/settings" \
>   -H "Authorization: Bearer $SIMMER_API_KEY" \
>   -H "Content-Type: application/json" \
>   -d '{"max_trades_per_day": 200}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

This instruction sends authenticated configuration to an external service, including wallet watchlists and live-trading parameters such as daily_cap, mirror_fraction, and venue. If executed automatically or manipulated by an attacker, it can reconfigure what wallets are followed and how much capital is deployed, materially altering trading behavior.

Content

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

bash
# Set your watchlist via the Simmer API
curl -X PATCH "https://api.simmer.markets/api/sdk/reactor/config" \
  -H "Authorization: Bearer $SIMMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{

Session Persistence

Medium
Category
Rogue Agent
Confidence
82% confidence
Finding

Use of nohup to keep the process running creates session persistence for a continuously polling trading bot. While not inherently malicious, persistence increases blast radius by allowing unattended operation, repeated external actions, and reduced user visibility if the process continues after the initiating session ends.

Content

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

python copytrading_trader.py --reactor

Plain shell (will not auto-restart)

nohup python copytrading_trader.py --reactor > reactor.log 2>&1 &

text

Set `REACTOR_POLL_INTERVAL_SECONDS` to tune the polling cadence (default 2s).

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The tunable label "Max bet per trade" uses USD as the fixed currency unit, which imposes a locale-specific assumption in user-facing configuration. The file does not offer a currency choice or document that the skill is intentionally US-dollar-specific.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring states the default mode 'never sells existing positions', but the implementation enables whale-exit selling by default unless --no-whale-exits is passed. In a live trading skill, this mismatch can cause unintended real-money sells and liquidation of positions the operator expected to be protected, creating a dangerous operator-deception/configuration risk.

Content

No source excerpt is available for this finding.

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · copytrading_trader.py (reported line 615)May include surrounding context.

python
# managed, external, and (future) OWS wallet backends transparently.
#
# Two invocation shapes:
#   python copytrading_trader.py --reactor          # loop forever, 2s cadence
#   python copytrading_trader.py --reactor --once   # single poll, exit (cron)
#
# Loop mode is recommended: supervised process (launchctl, systemd, tmux,

Vague Triggers

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The 'When to Use This Skill' section includes broad phrases like 'Check what positions a wallet holds' and 'Follow specific trader addresses' without clearly constraining that these requests must be about Polymarket copytrading. Those phrases overlap with common portfolio-inspection intents and could cause unintended invocation outside this skill's narrow domain.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This manifest describes a copytrading skill with sensitive trading behavior, but it does not specify any trigger phrases, invocation scope, or exclusion conditions. For manifest files, the absence of clear activation boundaries can make it unclear when the skill should activate versus remain dormant.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The dependency specifier simmer-sdk>=0.11.1 is unpinned, so installs may resolve to newer versions with unreviewed code or breaking behavior. In a trading-related skill that mirrors positions and may interact with on-chain signal infrastructure, a compromised or malicious upstream release could directly affect trade execution, wallet interactions, or sensitive runtime behavior.

Content

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

text
simmer-sdk>=0.11.1
packaging>=20

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The dependency specifier packaging>=20 allows any newer version to be installed, which weakens build reproducibility and increases supply-chain exposure to unexpected upstream changes. Although packaging is generally lower risk than a trading SDK, an unreviewed dependency update can still cause operational failures or introduce malicious code if the package ecosystem is compromised.

Content

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

text
simmer-sdk>=0.11.1
packaging>=20

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This code file contains multiple tests and comments describing live trading behavior, preflight checks, client construction side effects, and auto-routing from sim to polymarket, but the file itself provides no user-facing warning, confirmation, or explicit disclosure about those safety-relevant operations. Under the code-file criteria, subprocesses or network calls are not required for a finding when the code drives or documents potentially impactful operations without any visible disclosure in code comments, prints, or prompts.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_venue_routing.py:124