Back to skill

Security audit

Polymarket 24h Weather Distribution Trader

Security checks for vulnerabilities and agentic risk

Overview

This skill is openly a real-money trading bot, but its advertised safeguards do not fully match the code and could allow unintended financial exposure.

Install only if you are comfortable giving this skill trading authority and reviewing the strategy yourself. Keep it in paper mode unless you deliberately want live Polymarket orders, use a limited API key or account where possible, and do not rely on the documented volume and open-position safeguards as complete risk controls.

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

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:218
Finding

Live trades can be generated from incomplete temperature distributions

Content
View full analysis
= 2: exact_bins_sorted = sorted(exact_bins, key=lambda tb: tb.bin_info["temp"]) total = sum(tb.price for tb in exact_bins_sorted) deviation = total - 1.0 # positive = overpriced, negative = underpriced if abs(deviation) > SUM_TOLERANCE: ``` ### Technical Analysis The code assumes that any group containing two or more exact-temperature markets is a complete, mutually exclusive, and collectively exhaustive probability distribution. It then compares the sum of those markets with `1.0`. However, market discovery, question parsing, city parsing, and date parsing can produce only a subset of the actual bins. For example, a distribution containing markets for 8°C, 9°C, 10°C, and 11°C may be represented internally by only the 8°C and 9°C markets if the other markets are not returned by keyword search or do not match the parsing expressions. The sum of an incomplete subset is not mathematically required to equal 100%. Consequently, the code can incorrectly classify an ordinary partial sum as a pricing violation. The resulting opportunity is subsequently eligible for order execution, including real Polymarket execution when the process is started with `--live`. No attacker obtains operating-system privileges through this issue. The affected privilege is the trading authority associated with `SIMMER_API_KEY`, and the vulnerable scope includes any live funds accessible through that trading account. ### Attack Path 1. A city and date have more than two mutually exclusive temperature outcomes. 2. Market discovery or parsing includes at least two exact bins but omits one or more other valid outcomes. 3. The code treats the incomplete set as a complete distribution. 4. Its partial sum differs from ...[truncated 957 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:327
Finding

Configured minimum-volume safeguard is not enforced

Content
View full analysis
tuple[bool, str]: p = getattr(market, "current_probability", None) if not isinstance(p, (int, float)): return False, "missing probability" spread_cents = getattr(market, "spread_cents", None) if isinstance(spread_cents, (int, float)) and spread_cents / 100 > MAX_SPREAD: return False, f"Spread {spread_cents/100:.1%} > {MAX_SPREAD:.1%}" resolves_at = getattr(market, "resolves_at", None) if resolves_at: try: resolves = datetime.fromisoformat(resolves_at.replace("Z", "+00:00")) days = (resolves - datetime.now(timezone.utc)).days if days < MIN_DAYS: return False, f"Only {days} days to resolve" except Exception: pass return True, "ok" ``` ### Technical Analysis `SIMMER_MIN_VOLUME` is documented as a minimum market-volume filter and is exposed as an operator-adjustable tunable. Although the value is loaded into `MIN_VOLUME`, neither `valid_market()` nor `find_markets()` retrieves or validates market volume. This creates a discrepancy between the advertised control and actual execution. Markets with no volume information or volume below the configured threshold can proceed to signal generation and order submission. Low-volume markets are generally more susceptible to price manipulation, poor execution, inability to exit, and misleading displayed probabilities. A malicious market participant could potentially move a thin market enough to create an ...[truncated 1369 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:469
Finding

Maximum concurrent-position limit resets on every execution

Content
View full analysis
= MAX_POSITIONS: break market = opp[0] side, size, reasoning = compute_signal(market, opp) if not side: print(f" [skip] {reasoning}") continue ok, why = context_ok(client, market_id) if not ok: print(f" [skip] {why}") continue try: r = client.trade( market_id=market_id, side=side, amount=size, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, reasoning=reasoning, ) tag = "(sim)" if r.simulated else "(live)" status = "OK" if r.success else f"FAIL:{r.error}" print(f" [trade] {side.upper()} ${size} {tag} {status} — {reasoning[:110]}") if r.success: placed += 1 ``` ### Technical Analysis The documentation describes `SIMMER_MAX_POSITIONS` as the maximum number of concurrent open positions. The implementation instead counts only successful orders submitted during the current process invocation. The counter starts at zero every time `run()` executes. The program never queries existing open positions, pending orders, or prior exposure. Therefore, an account with the maximum intended number of positions can open up to another `MAX_POSITIONS` positions on every subsequent invocation. This is especially relevant to managed automation, manual repeated execution, or an operator retrying after partial failures. It also means that multiple simultaneously running instances can each independently consume the full nominal position allowance. No system-level privilege is acquired. The affected privilege is the ability to place trades through `SIMMER_API_KEY`, and th ...[truncated 1179 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly requires a high-value credential (SIMMER_API_KEY) and describes live trading capability, but it does not declare any explicit tool scope or permissions boundaries. That mismatch is risky because an agent platform may grant broader environment or execution access than intended, increasing the chance of credential exposure or unauthorized trading actions if the skill is invoked in a permissive runtime.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
## The Edge: Distribution Arbitrage for Temperature Markets

In traditional markets, discrete outcome probabilities must sum to 1.0 — this is a fundamental axiom. On Polymarket, each temperature bin trades independently with its own order book and liquidity. Retail treats each bin as an isolated bet without checking the full distribution.

### Violation Type 1: Sum Deviation

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest requires a sensitive API credential (SIMMER_API_KEY) and configures an automated trading entrypoint, but it does not provide any user-facing disclosure about credential use, trading authority, or financial risk. In a trading skill, this omission is materially important because users may supply live credentials without understanding that the agent can place automated trades and incur losses.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.