Back to skill

Security audit

Polymarket Bundle Overwatch Bo3 Trader

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed trading skill, but its live-trading safeguards are under-enforced enough that users should review it before installing.

Install only if you are comfortable reviewing and controlling a live trading bot. Keep it in paper mode unless you have verified the risk checks, pin the SDK dependency, use a tightly scoped and limited API key, and treat --live as permission to place real-money Polymarket orders.

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

Error
Location
trader.py:232
Finding

Market safety checks fail open when context retrieval or validation raises an exception

Content
View full analysis
tuple[bool, str]: """Check flip-flop and slippage safeguards.""" try: ctx = client.get_market_context(market_id) if not ctx: return True, "no context" if ctx.get("discipline", {}).get("is_flip_flop"): reason = ctx["discipline"].get("flip_flop_reason", "recent reversal") return False, f"Flip-flop: {reason}" slip = ctx.get("slippage", {}) if isinstance(slip, dict) and slip.get("slippage_pct", 0) > 0.15: return False, f"Slippage {slip['slippage_pct']:.1%}" for w in ctx.get("warnings", []): safe_print(f" [warn] {w}") except Exception as e: safe_print(f" [ctx] {market_id}: {e}") return True, "ok" ``` The result is then used to authorize the trade: ```python ok, why = context_ok(client, bo3_market.id) if not ok: safe_print(f" [skip] {why}") continue try: r = client.trade( market_id=bo3_market.id, side=side, amount=size, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, reasoning=reasoning, ) ``` ### Technical Analysis `context_ok()` is intended to prevent trades when the SDK reports flip-flop behavior or excessive slippage. However, it returns approval in both of these unsafe states: 1. `get_market_context()` returns no context. 2. Context retrieval or parsing raises any exception. The broad `except Exception` handler records the error but then falls through to `return True, "ok"`. This is a fail-open authorization design. Network errors, authentication failures, SDK response changes, malformed context objects, or unexpected field types therefore disable the safeguards instead of stopping the ...[truncated 1295 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:379
Finding

Documented liquidity and concurrent-position risk limits are not enforced

Content
View full analysis
list: """Find active Overwatch 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}") ``` The position limit only counts successful orders during the current process invocation: ```python placed = 0 for bo3_market, violation, implied, actual in opportunities: if placed >= MAX_POSITIONS: break side, size, reasoning = compute_signal(bo3_market, violation, implied, actual) if not side: safe_print(f" [skip] {reasoning}") continue ok, why = context_ok(client, bo3_market.id) if not ok: safe_print(f" [skip] {why}") continue try: r = client.trade( ...[truncated 2435 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding

Unpinned third-party SDK executes with access to the trading credential

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill explicitly requires a high-value credential (SIMMER_API_KEY) and describes trading functionality, but it does not declare any explicit tool scope or permissions boundary. That creates an avoidable trust gap: an agent/runtime may grant broader environment or execution access than the skill actually needs, increasing the blast radius if the skill is modified, misused, or paired with unsafe code.

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 33)May include surrounding context.

md
This constraint must hold. When it does not:

1. **Retail prices markets in isolation** -- users bet on BO3 outcomes without checking individual game markets, or vice versa, causing the joint distribution to drift
2. **Resolution forces convergence** -- as each game is played, the BO3 probability must mechanically update; any mispricing is guaranteed to collapse
3. **Niche Overwatch markets have thin coverage** -- lower liquidity means fewer participants enforcing the cross-market constraint
4. **Same structural edge as CS2 maps** -- this is the same arbitrage pattern documented in CS2 map winner vs series winner markets, applied to the Overwatch ecosystem

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module caches a single global SimmerClient in _client and only initializes it once. If the process first calls get_client(live=False) and later calls get_client(live=True), it will return the previously cached simulated client instead of creating a real Polymarket client, so runtime behavior no longer matches the live argument or the safety claims in the docstring.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.