Back to skill

Security audit

Polymarket Celebrity Social Trader

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed prediction-market trading bot, but its live-trading safety boundaries and advertised risk controls are not reliably enforced.

Install only if you are comfortable reviewing and hardening the trading code first. Use a dedicated, limited Simmer credential, keep live mode disabled unless intentionally trading, pin the SDK dependency, and fix the client-mode and risk-limit enforcement issues before allowing real-money execution.

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)

T08 · Insecure Dependencies

Warning
Location
clawhub.json:5
Finding
Unpinned Third-Party Trading Dependency## Vulnerability Details **File Location**: `clawhub.json:5-10` **Vulnerability Type**: Supply-chain exposure through an unpinned executable dependency **Risk Level**: Medium ### Vulnerable Code ```json "requires": { "env": [ "SIMMER_API_KEY" ], "pip": [ "simmer-sdk" ] } ``` ### Technical Analysis The project installs `simmer-sdk` without specifying an exact version or package integrity hash. Consequently, future installations can resolve to a different release than the one originally reviewed. This dependency operates within the same Python process as the skill and is explicitly given `SIMMER_API_KEY`. It also implements the market-query and trade-submission interfaces. A compromised, malicious, or unexpectedly changed release would therefore execute with the skill's full process privileges and have access to its trading credential. No evidence was found that the currently referenced package is malicious. The vulnerability is the absence of controls ensuring that the reviewed dependency is the dependency installed later. ### Attack Path 1. An attacker compromises the dependency's package-publishing account or otherwise causes an unsafe release to be resolved. 2. A user or automation environment installs the skill and resolves the unversioned `simmer-sdk` requirement. 3. The malicious package executes during installation or when imported by `trader.py`. 4. At runtime, the package receives `SIMMER_API_KEY` through the `SimmerClient` constructor. 5. The package can exfiltrate the credential, manipulate market data, alter submitted orders, or execute arbitrary actions available to the Python process. ### Impact Assessment Exploitation could expose the Simmer API credential and its associated trading authority. In live mode, this could allow unauthorized prediction-market transactions and financial loss. Because Python dependencies execute with the privileges of the invoking process, compr ...[truncated 107 chars]
Remediation
## Remediation Suggestions - Pin `simmer-sdk` to an exact, reviewed version rather than accepting any available release. - Maintain a lock file containing exact versions for direct and transitive dependencies. - Require package hashes during installation, such as through a hash-locked requirements file. - Review package ownership, release provenance, and source changes before updating the pinned version. - Install dependencies from a controlled package index or approved artifact repository. - Run the trader under a dedicated, least-privileged account with access only to required resources. - Scope and rotate `SIMMER_API_KEY` where supported, and monitor it for unexpected trading activity.

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:39
Finding
Cached Client Can Retain Live-Trading Mode During a Later Paper Run## Vulnerability Details **File Location**: `trader.py:39-72` **Vulnerability Type**: Unsafe global client lifecycle and trading-mode confusion **Risk Level**: High ### Vulnerable Code ```python _client: SimmerClient | None = None def get_client(live: bool = False) -> SimmerClient: """ live=False → venue="sim" (paper trades — safe default). live=True → venue="polymarket" (real trades, only with --live flag). """ global _client, MAX_POSITION, MIN_VOLUME, MAX_SPREAD, MIN_DAYS, MAX_POSITIONS, YES_THRESHOLD, NO_THRESHOLD, MIN_TRADE if _client is None: venue = "polymarket" if live else "sim" _client = SimmerClient( api_key=os.environ["SIMMER_API_KEY"], venue=venue, ) # Load tunable overrides set via the Simmer UI (SIMMER_* vars only). if live: _client.live = True try: _client.apply_skill_config(SKILL_SLUG) except AttributeError: pass # apply_skill_config only available in Simmer runtime # Re-read params in case apply_skill_config updated os.environ. MAX_POSITION = float(os.environ.get("SIMMER_MAX_POSITION", str(MAX_POSITION))) MIN_VOLUME = float(os.environ.get("SIMMER_MIN_VOLUME", str(MIN_VOLUME))) MAX_SPREAD = float(os.environ.get("SIMMER_MAX_SPREAD", str(MAX_SPREAD))) MIN_DAYS = int(os.environ.get( "SIMMER_MIN_DAYS", str(MIN_DAYS))) MAX_POSITIONS = int(os.environ.get( "SIMMER_MAX_POSITIONS", str(MAX_POSITIONS))) YES_THRESHOLD = float(os.environ.get("SIMMER_YES_THRESHOLD", str(YES_THRESHOLD))) NO_THRESHOLD = float(os.environ.get("SIMMER_NO_THRESHOLD", str(NO_THRESHOLD))) MIN_TRADE = float(os.environ.get("SIMMER_MIN_TRADE", str(MIN_TRADE))) return _client ``` ### Technical Analysis The client is stored in a single process-global ...[truncated 1891 chars]
Remediation
## Remediation Suggestions - Avoid a process-global client and create a new client for each run. - Alternatively, cache separate clients keyed by venue, such as `sim` and `polymarket`. - Store the selected venue alongside the cached client and reject any request whose mode differs. - Before every trade, assert that the client venue matches the current `live` argument. - Derive the displayed mode from the actual client configuration rather than only from the function argument. - Require a separate live-trading credential or an additional explicit confirmation mechanism for live execution. - Add a regression test that initializes live mode and then requests paper mode in the same process, verifying that the second trade is simulated.

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:29
Finding
Declared Financial Risk Controls Are Not Fully Enforced## Vulnerability Details **File Location**: `trader.py:29-37`, `trader.py:255-263`, and `trader.py:286-317` **Vulnerability Type**: Incomplete and inconsistent enforcement of trading limits **Risk Level**: Medium ### Vulnerable Code Risk parameters are declared, including a minimum-volume threshold and position limits: ```python MAX_POSITION = float(os.environ.get("SIMMER_MAX_POSITION", "20")) MIN_VOLUME = float(os.environ.get("SIMMER_MIN_VOLUME", "3000")) MAX_SPREAD = float(os.environ.get("SIMMER_MAX_SPREAD", "0.12")) MIN_DAYS = int(os.environ.get( "SIMMER_MIN_DAYS", "3")) MAX_POSITIONS = int(os.environ.get( "SIMMER_MAX_POSITIONS", "10")) YES_THRESHOLD = float(os.environ.get("SIMMER_YES_THRESHOLD", "0.38")) NO_THRESHOLD = float(os.environ.get("SIMMER_NO_THRESHOLD", "0.62")) MIN_TRADE = float(os.environ.get("SIMMER_MIN_TRADE", "5")) ``` Position sizing applies a minimum floor without subsequently enforcing the maximum: ```python if p <= YES_THRESHOLD: conviction = min(1.0, (YES_THRESHOLD - p) / YES_THRESHOLD * bias) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) edge = YES_THRESHOLD - p return "yes", size, f"YES {p:.0%} edge={edge:.0%} bias={bias:.2f}x size=${size} — {q[:65]}" if p >= 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]}" ``` The execution loop limits successful orders in the current run, but does not inspect existing open positions: ```python placed = 0 for m in markets: if placed >= MAX_POSITIONS: break side, size, reasoning = compute_signal(m) if not side: print(f" [skip] {reasoning}") continue ok, why = context_ok(client, m ...[truncated 3281 chars]
Remediation
## Remediation Suggestions - Validate market volume before generating or submitting an order: ```python if market.volume is None or market.volume < MIN_VOLUME: return None, 0, "Market volume below configured minimum" ``` - Confirm the actual SDK market-volume field and its currency and units before implementing the comparison. - Query existing open positions before the trading loop and calculate remaining capacity from the total number of open positions. - Recheck open-position capacity immediately before submission to reduce race conditions in concurrent runs. - Apply both lower and upper sizing bounds: ```python size = min(MAX_POSITION, max(MIN_TRADE, round(conviction * MAX_POSITION, 2))) ``` - Reject configuration where `MIN_TRADE` exceeds `MAX_POSITION` instead of silently producing contradictory behavior. - Validate all numeric settings at startup, including nonnegative values and sensible threshold ordering. - Add tests covering low-volume markets, repeated runs with existing positions, and configurations where the minimum trade exceeds the maximum position.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (2)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill references use of a high-value environment credential (`SIMMER_API_KEY`) and trading/execution behavior, but it does not declare an explicit tool scope or permissions boundary. In an agent platform, missing scope declarations can allow the skill to be invoked with broader-than-necessary access to environment variables or execution capabilities, increasing the chance of credential exposure or unintended live trading if composed with other tools.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger keywords are broad, celebrity-heavy, and overlap with common user conversations, making accidental activation plausible. In this skill's context, unintended triggering is more dangerous because the skill is tied to market discovery and possible trade execution, so benign discussion about celebrities or social media could steer an agent into using trading logic unnecessarily.

Static analysis

No suspicious patterns detected.