Back to skill

Security audit

Polymarket 24h Price Curve Arb Trader

Security checks for vulnerabilities and agentic risk

Overview

This trading skill is not malicious, but it should be reviewed because it can place real trades with an API key and several documented safety limits are missing or inconsistent.

Install only if you are comfortable giving this skill a scoped Simmer/Polymarket trading key. Keep it in paper mode until the liquidity filter, position-limit semantics, and threshold default are corrected or explicitly accepted, and prefer a pinned reviewed simmer-sdk version before using live trading.

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)

T08 · Insecure Dependencies

Warning
Location
clawhub.json:6
Finding

Unpinned Third-Party Trading Dependency Creates a Supply-Chain Risk

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:303
Finding

Configured Minimum Market 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" ``` The documented control is: ```markdown | `SIMMER_MIN_VOLUME` | `5000` | Min market volume filter (USD) | ``` ### Technical Analysis `SIMMER_MIN_VOLUME` is presented as a risk-control tunable and is loaded into application state, but it is never used in market discovery, curve construction, signal computation, or final validation. A market can therefore pass `valid_market()` regardless of whether it has zero, missing, or extremely low trading volume. Low-volume markets are easier to move with small orders and can display stale or manipulable probabilities. Since the strategy treats probability inconsistencies as trading signals, failure to enforce liquidity requirements makes it possible for ...[truncated 1151 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:431
Finding

Maximum Position Count Only Limits Orders in the Current Run

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 except Exception as e: print(f" [error] {market_id}: {e}") ``` The setting is documented as: ```markdown | `SIMMER_MAX_POSITIONS` | `8` | Max concurrent open positions | ``` ### Technical Analysis The `placed` counter starts at zero every time `run()` executes and counts only successful orders submitted during that invocation. The implementation does not query the account's existing open positions, pending orders, or current exposure. As a result, `MAX_POSITIONS` is an order-per-run limit rather than the documented concurrent-position limit. Repeated manual executions or later automation can add up to `MAX_POSITIONS` successful orders on every run while prior positions remain open. The code also does not reserve capacity atomically. Concurrent instances could each observe their own local counter as zero and submit orders in ...[truncated 1029 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
trader.py:50
Finding

Documented Violation Threshold Does Not Match the Executable Default

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
81% confidence
Finding

The skill references a high-value environment credential (SIMMER_API_KEY) but does not declare any explicit tool scope or permissions boundary for environment access. In agent platforms, undeclared access to environment variables weakens least-privilege controls and can allow the skill to read sensitive secrets it was not narrowly scoped to use, increasing the chance of credential exposure or misuse if the skill is modified or composed with other components.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

This manifest requires the sensitive environment variable SIMMER_API_KEY, but the file provides no warning or disclosure about credential use, storage, or the fact that the skill will operate with authenticated access. Because this is a trading-related skill, omission of any warning about use of an API key could leave users unaware of the sensitivity of the permission they are granting.

Content

No source excerpt is available for this finding.