Back to skill

Security audit

Polymarket Candle Marubozu Trader

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Polymarket trading bot, but its live/paper mode handling and risk controls could mislead users and expose them to unintended real trades.

Review carefully before installing. Use a limited, separate credential, keep autostart disabled until tested, run only in paper mode in a fresh process, and do not enable live trading until the client-mode cache bug, minimum-volume enforcement, interval-adjacency validation, and dependency pinning are fixed.

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
trader.py:55
Finding

Cached Client Can Retain Live-Trading Mode During a Paper-Trading Run

Content
View full analysis
SimmerClient: """ live=False -> venue="sim" (paper trades -- safe default). live=True -> venue="polymarket" (real trades, only with --live flag). """ global _client, MAX_POSITION, MIN_VOLUME, MAX_SPREAD, MIN_DAYS, MAX_POSITIONS global YES_THRESHOLD, NO_THRESHOLD, MIN_TRADE, MARU_THRESHOLD if _client is None: venue = "polymarket" if live else "sim" _client = SimmerClient( api_key=os.environ["SIMMER_API_KEY"], venue=venue, ) if live: _client.live = True try: _client.apply_skill_config(SKILL_SLUG) except AttributeError: pass # apply_skill_config only available in Simmer runtime # Re-read params in case apply_skill_config updated os.environ. MAX_POSITION = float(os.environ.get("SIMMER_MAX_POSITION", str(MAX_POSITION))) MIN_VOLUME = float(os.environ.get("SIMMER_MIN_VOLUME", str(MIN_VOLUME))) MAX_SPREAD = float(os.environ.get("SIMMER_MAX_SPREAD", str(MAX_SPREAD))) MIN_DAYS = int(os.environ.get( "SIMMER_MIN_DAYS", str(MIN_DAYS))) MAX_POSITIONS = int(os.environ.get( "SIMMER_MAX_POSITIONS", str(MAX_POSITIONS))) YES_THRESHOLD = float(os.environ.get("SIMMER_YES_THRESHOLD", str(YES_THRESHOLD))) NO_THRESHOLD = float(os.environ.get("SIMMER_NO_THRESHOLD", str(NO_THRESHOLD))) MIN_TRADE = float(os.environ.get("SIMMER_MIN_TRADE", str(MIN_TRADE))) MARU_THRESHOLD = float(os.environ.get("SIMMER_MARU_THRESHOLD", str(MARU_THRESHOLD))) return _client ``` ### Technical Analysis The module stores a single `SimmerClient` instance in the global `_client` variable ...[truncated 1842 chars]
Remediation
View remediation
SimmerClient: venue = "polymarket" if live else "sim" if venue not in _clients: _clients[venue] = SimmerClient( api_key=os.environ["SIMMER_API_KEY"], venue=venue, ) client = _clients[venue] if getattr(client, "venue", venue) != venue: raise RuntimeError("Trading client venue does not match requested mode") return client ``` - Alternatively, recreate the client whenever the requested mode differs from the cached client's mode. - Immediately before every call to `client.trade()`, enforce that the client's effective venue matches the requested run mode. - Avoid relying on a mutable SDK-specific `live` attribute as the only safety control. - Add regression tests that execute a live initialization followed by a paper run in the same process and verify that the second run cannot use the live venue. - Make the mode part of the immutable execution context and include the verified venue in trade logs. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:25
Finding

Configured Minimum-Volume Trading Safeguard Is Not Enforced

Content
View full analysis
list: """Find active crypto interval markets via keyword search + get_markets fallback.""" seen, unique = set(), [] # 1. Keyword search for kw in KEYWORDS: try: for m in client.find_markets(query=kw): if m.id not in seen: seen.add(m.id) unique.append(m) except Exception as e: safe_print(f"[search] {kw!r}: {e}") # 2. Fallback: scan broad market list for interval matches try: for m in client.get_markets(limit=200): mid = getattr(m, "id", None) q = getattr(m, "question", "") if mid and mid not in seen and _INTERVAL_RE.match(q.strip()): seen.add(mid) unique.append(m) except Exception as e: safe_print(f"[fallback] get_markets: {e}") return unique ``` The execution path proceeds from signal evaluation to trade placement without applying `MIN_VOLUME`: ```python for m, maru_dir, maru_str in maru_targets: if placed >= MAX_POSITIONS: break side, size, reasoning = compute_signal(m, maru_dir, maru_str) if not side: safe_print(f" [skip] {reasoning}") continue ok, why = context_ok(client, m.id) if not ok: safe_print(f" [skip] {why}") continue try: r = client.trade( market_id=m.id, side=side, amount=size, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, ...[truncated 1767 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:157
Finding

Continuation Logic Treats Any Subsequent Listed Market as the Next Five-Minute Interval

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
clawhub.json:7
Finding

Privileged Trading SDK Dependency Is Not Version-Pinned

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill declares access to high-value environment credentials such as SIMMER_API_KEY and describes live trading capability, but it does not define an explicit tool/permission scope like permissions or allowed-tools. That creates an overprivileged execution model where an agent or runtime may expose environment access more broadly than intended, increasing the chance of credential misuse or unintended live-trade actions if the surrounding platform grants default capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest declares a required API key for a managed automated trading skill, but the manifest itself provides no user-facing disclosure about what the credential will be used for or that the skill can autonomously place trades. In the context of a live trading bot, this increases the risk of users supplying sensitive credentials without understanding financial exposure, making accidental loss or misuse more likely.

Content

No source excerpt is available for this finding.