Back to skill

Security audit

Polymarket 48h Nba Game Structure Trader

Security checks for vulnerabilities and agentic risk

Overview

This skill is openly a trading bot, but some advertised live-trading safeguards are not actually enforced, so users should review it carefully before granting trading access.

Install only with a least-privilege Simmer/Polymarket key and account-side spending limits. Treat the advertised volume and concurrent-position safeguards as unreliable until fixed, and test in paper mode before any live use.

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:436
Finding

Configured minimum market volume safeguard is never enforced

Content
View full analysis
tuple[bool, str]: """Check basic market quality gates.""" 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 a configurable tunable. The application reads it into `MIN_VOLUME`, but no execution path uses that value when validating markets. Consequently, any market that has a valid probability and passes the spread and resolution-time checks can reach `client.trade()`, regardless of its liquidity or trading volume. This is particularly dangerous because the program supports real-USDC trading when invoked with `--live`. Low-volume markets are more susceptible to price manipulation and may have insufficient depth for safe execution. The presence of a documented but inactive c ...[truncated 1155 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:588
Finding

Maximum concurrent position limit resets on every invocation

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}") ``` ### Technical Analysis The documentation describes `SIMMER_MAX_POSITIONS` as the maximum number of concurrent open positions. The implementation instead initializes a local `placed` counter to zero each time `run()` executes and increments it only for successful trades placed during that invocation. The program never retrieves the account's existing open positions. It also does not subtract existing exposure from the configured cap or prevent repeated runs from adding positions beyond that cap. Therefore, `MAX_POSITIONS` is a per-process order limit rather than an account-level concurrent-position limit. Repeated manual, scheduled, or managed-automaton execution can continually reset the counter. ### Attack P ...[truncated 1139 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
clawhub.json:6
Finding

Unpinned third-party trading dependency receives API credentials and executes trades

Content
View full analysis
SimmerClient: global _client, MAX_POSITION, MIN_VOLUME, MAX_SPREAD, MIN_DAYS, MAX_POSITIONS global YES_THRESHOLD, NO_THRESHOLD, MIN_TRADE, MIN_INCONSISTENCY 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 ``` It also controls trade submission: ```python r = client.trade( market_id=market_id, side=side, amount=size, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, reasoning=reasoning, ) ``` ### Technical Analysis The project declares `simmer-sdk` without an exact version, lockfile, or integrity hash. Package resolution can therefore install a newer release than the one originally reviewed. This dependency occupies a security-sensitive trust boundary. Imported package code executes in the process, receives `SIMMER_API_KEY`, retrieves market information, applies configuration, and submits simulated or live trades. A compromised upstream release, package-index account, distribution artifact, or dependency chain could therefore access the credential and alter trading behavior. The reviewed project contains no evidence that the current `simmer-sdk` package is ...[truncated 1324 chars]
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
84% confidence
Finding

The skill declares a required high-value credential (SIMMER_API_KEY) and implies environment access, but it does not define an explicit tool/permission scope such as permissions or allowed-tools. That creates an avoidable least-privilege gap: an agent runtime may grant broader environment access than necessary, increasing the chance that secrets are exposed to unrelated logic, prompts, or future modifications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest explicitly requires a sensitive API credential (SIMMER_API_KEY) and configures an automated trading entrypoint, but the file provides no user-facing disclosure that the skill will connect to an external trading service and place market trades. In a trading skill, undisclosed credential use increases the risk of users granting powerful API access without understanding the external actions the agent can take, which can lead to unauthorized or unexpected trading activity and financial loss.

Content

No source excerpt is available for this finding.