Back to skill

Security audit

Polymarket Catastrophe Trader

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Polymarket trading bot, but it needs review because some advertised trading safeguards are not actually enforced.

Install only if you understand it can submit real Polymarket trades when run with --live. Keep it in paper mode until the minimum-volume filter and final order-size cap are fixed, pin the simmer-sdk dependency to a reviewed version, and use a limited trading key with only the balance and permissions you are willing to risk.

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

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:93
Finding

Declared Minimum-Volume Safeguard Is Not Enforced

Content
View full analysis
list: """Find active markets matching strategy keywords, deduplicated.""" seen, unique = set(), [] 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: print(f"[search] {kw!r}: {e}") return unique ``` The resulting markets are subsequently passed to `compute_signal()` and then to `client.trade()` without a volume check. ### Technical Analysis `SIMMER_MIN_VOLUME` is documented as a minimum market-volume filter and is loaded into `MIN_VOLUME`. However, `find_markets()` only filters duplicate market IDs. Neither this function nor the later signal and execution flow compares a market's volume against `MIN_VOLUME`. Consequently, the configured safeguard has no effect. This is particularly relevant to live prediction-market trading because low-volume markets can have unreliable prices, shallow order books, poor execution, and greater susceptibility to price manipulation. The issue also creates a discrepancy between the documented security posture and actual behavior: operators may reasonably believe that markets below the configured volume threshold cannot be traded. ### Attack Path 1. An attacker creates or identifies a low-volume Polymarket market containing one of the monitored catastrophe-related keywords. 2. The market is returned by `client.find_markets()`. 3. `find_markets()` accepts it because it checks only whether the market ID has already been seen. 4. If its displayed probability, spread, and resolu ...[truncated 822 chars]
Remediation
View remediation
list: seen, unique = set(), [] for kw in KEYWORDS: try: for market in client.find_markets(query=kw): if market.id in seen: continue volume = getattr(market, "volume", None) if volume is None: print(f" [skip] {market.id}: volume unavailable") continue try: volume = float(volume) except (TypeError, ValueError): print(f" [skip] {market.id}: invalid volume") continue if volume < MIN_VOLUME: continue seen.add(market.id) unique.append(market) except Exception as e: print(f"[search] {kw!r}: {e}") return unique ``` 2. Fail closed when volume is missing, malformed, negative, stale, or supplied in an unexpected unit. 3. Confirm the exact volume attribute and units exposed by the pinned SDK version. 4. Repeat the check immediately before live execution if market metadata can change between discovery and trading. 5. Add tests for volume below, equal to, and above `MIN_VOLUME`, as well as missing and malformed values. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:326
Finding

Minimum Trade Floor Can Exceed the Maximum Position Limit

Content
View full analysis
= NO_THRESHOLD: conviction = min(1.0, (p - NO_THRESHOLD) / (1 - NO_THRESHOLD) * bias) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) edge = p - NO_THRESHOLD return "no", size, f"NO YES={p:.0%} edge={edge:.0%} bias={bias:.2f}x size=${size} — {q[:65]}" ``` ### Technical Analysis The calculated conviction component cannot exceed `MAX_POSITION`, but the final expression applies only a lower bound: ```python max(MIN_TRADE, calculated_size) ``` It does not apply an upper bound after introducing `MIN_TRADE`. If `SIMMER_MIN_TRADE` is configured above `SIMMER_MAX_POSITION`, the resulting order amount will equal `MIN_TRADE` and therefore exceed the documented maximum position size. The implementation contradicts the documentation in `SKILL.md`, which states that sizing is capped at `MAX_POSITION`. No startup validation requires `MIN_TRADE` to be less than or equal to `MAX_POSITION`. ### Attack Path 1. An unsafe deployment configuration, environment injection, or managed configuration update sets `SIMMER_MIN_TRADE` above `SIMMER_MAX_POSITION`. 2. The application accepts both values without checking their relationship. 3. A discovered market crosses either the YES or NO signal threshold. 4. `compute_signal()` evaluates `max(MIN_TRADE, conviction * MAX_POSITION)`. 5. The returned amount exceeds `MA ...[truncated 648 chars]
Remediation
View remediation
MAX_POSITION: raise ValueError( "SIMMER_MIN_TRADE must not exceed SIMMER_MAX_POSITION" ) ``` 2. Apply both lower and upper bounds to every calculated order: ```python calculated = round(conviction * MAX_POSITION, 2) size = min(MAX_POSITION, max(MIN_TRADE, calculated)) ``` 3. Validate configuration again after `apply_skill_config()` because that call may update environment-backed values. 4. Add a final independent amount check immediately before `client.trade()`. 5. Add unit tests covering equal limits, an oversized minimum, negative values, non-finite numbers, and ordinary threshold-boundary calculations. ]]>

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding

Security-Sensitive Trading SDK Is Not Version-Pinned

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

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill references use of an environment variable credential (SIMMER_API_KEY) and therefore has code-capable access to sensitive env data, but it does not declare an explicit tool scope such as permissions or allowed-tools. That mismatch weakens least-privilege controls and can let the runtime expose broader capabilities than the skill actually needs, which is especially relevant here because the credential grants trading authority for simulated or live financial actions.

Content

No source excerpt is available for this finding.