Back to skill

Security audit

Polymarket Solana Onchain

Security checks for vulnerabilities and agentic risk

Overview

This trading skill can run live trades automatically on a schedule using a required API key, with under-disclosed risk controls.

Install only if you intentionally want recurring automated live trading. Use a narrowly scoped, revocable SIMMER_API_KEY with account-side spending limits, verify or disable the cron/--live automation, and prefer dry-run mode until the dependency pinning, live-trade confirmation, fail-closed safeguards, and cumulative loss limits are improved.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (3)

T06 · System Persistence

Error
Location
clawhub.json:7
Finding
Unattended Scheduled Live Trading Creates Persistent Financial Side Effects<![CDATA[ ## Vulnerability Details **File Location**: `clawhub.json:7-11` **Vulnerability Type**: Persistent scheduled execution of live financial trades **Risk Level**: High ### Vulnerable Code ```json "cron": "*/10 * * * *", "automaton": { "managed": true, "entrypoint": "strategy.py", "args": ["--live"] } ``` ### Technical Analysis The package configures its managed entry point to run every ten minutes and explicitly supplies the `--live` argument. In `strategy.py`, this argument changes execution from dry-run mode to live trading mode. This creates persistent financial behavior that continues beyond a single interactive invocation. It is materially more privileged than collecting public blockchain signals or presenting proposed trades for approval. Although the documentation identifies `--live` as the way to execute real trades, the package configuration automatically selects it for every scheduled run. Each run can attempt up to four trades using the configured position size. There is no package-level cumulative expenditure limit, schedule expiration, or requirement for per-run confirmation. ### Attack Path 1. A user installs or enables the Skill with managed automation. 2. The platform registers the cron expression from `clawhub.json`. 3. Every ten minutes, the scheduler launches `strategy.py --live`. 4. The process obtains `SIMMER_API_KEY` from its environment. 5. The strategy collects signals and searches for qualifying markets. 6. If a non-neutral signal and eligible markets are found, the strategy submits real trades. 7. The sequence repeats indefinitely while the automation remains enabled. ### Impact Assessment The Skill can repeatedly use the user's trading authority without approval for each run. Under the default configuration, it may attempt up to four live trades of up to USD 20 each per run. Because execution occurs every ten minutes, financial losses, fees, and exposure can accumulate over time. The affected privilege is the au ...[truncated 247 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the default cron schedule and managed `--live` argument. - Configure managed or scheduled execution to use dry-run mode by default. - Require explicit, informed opt-in before enabling recurring live trading. - Require per-run or per-trade authorization for live financial actions. - Add a cumulative daily and lifetime spending ceiling independent of the per-trade limit. - Add an expiration time, maximum number of scheduled runs, and easily accessible kill switch. - Clearly disclose the schedule, live mode, maximum trade count, and maximum possible expenditure during installation. - Use a narrowly scoped and revocable API credential with strict account-side spending and venue restrictions. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
strategy.py:353
Finding
Trading Safeguard Fails Open When Context Validation Is Unavailable<![CDATA[ ## Vulnerability Details **File Location**: `strategy.py:353-365` **Vulnerability Type**: Fail-open authorization and risk validation **Risk Level**: High ### Vulnerable Code ```python def check_context(client, market_id: str) -> tuple[bool, str]: try: ctx = client._request("GET", f"/api/sdk/context/{market_id}") discipline = ctx.get("discipline", {}) if discipline.get("warning_level") == "severe": return False, "severe flip-flop" slippage = ctx.get("slippage", {}) if slippage: estimates = slippage.get("estimates", []) if estimates and estimates[0].get("slippage_pct", 0) > 0.15: return False, "high slippage" return True, "" except Exception: return True, "" # Don't block on context failure ``` The returned approval is consumed before live trading: ```python ok, reason = check_context(client, c["market_id"]) if not ok: log(f" ⛔ Skipped: {reason}") skip_reasons.append(reason) continue ``` A successful fail-open result permits the later call to `client.trade()`. ### Technical Analysis The context check is intended to reject markets with a severe discipline warning or estimated slippage above 15%. However, every exception is caught and converted into a successful authorization result. Exceptions may be caused by network failures, timeouts, service outages, malformed responses, unexpected response types, SDK errors, or incompatible API changes. Consequently, the absence of trustworthy risk data is treated as evidence that trading is safe. This is a fail-open control design. For a live financial operation, a failed prerequisite safety check should prevent execution rather than silently authorize it. ### Attack Path 1. The strategy identifies a candidate market during a live scheduled run. 2. The context API request fails or returns data that causes an exception. 3. The broad `except Exception` handler suppresses the fai ...[truncated 863 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Fail closed when context validation cannot be completed: ```python except Exception as exc: log(f"Context validation failed for {market_id}: {exc}") return False, "context unavailable" ``` - Validate that the response is a dictionary and that expected nested values have valid types. - Require fresh, successful context data before every live trade. - Use narrowly scoped exception handlers rather than catching every `Exception`. - Distinguish retryable availability failures from permanently malformed responses. - Add bounded retries with exponential backoff, but never authorize a trade merely because retries were exhausted. - Record structured audit logs for context failures and skipped trades without exposing credentials. - Add tests proving that timeouts, malformed JSON, missing fields, and SDK errors all block live execution. ]]>

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding
Unpinned Third-Party SDK Executes In Process with Access to the Trading Credential<![CDATA[ ## Vulnerability Details **File Location**: `clawhub.json:3-5`, `SKILL.md:41-45`, `SKILL.md:65`, and `strategy.py:402-413` **Vulnerability Type**: Unpinned security-sensitive dependency **Risk Level**: Medium ### Vulnerable Code Dependency declaration in `clawhub.json`: ```json "requires": { "pip": ["simmer-sdk"], "env": ["SIMMER_API_KEY"] } ``` Installation instruction in `SKILL.md`: ```bash pip install simmer-sdk ``` Credential use in `strategy.py`: ```python try: from simmer_sdk import SimmerClient except ImportError: print("Error: simmer-sdk not installed. Run: pip install simmer-sdk") sys.exit(1) api_key = os.environ.get("SIMMER_API_KEY") if not api_key: print("Error: SIMMER_API_KEY not set") sys.exit(1) client = SimmerClient(api_key=api_key, venue=VENUE, live=not dry_run) ``` ### Technical Analysis The dependency is specified only by package name, without an exact version, integrity hash, lock file, or constrained package source. Installation therefore resolves a mutable package release at installation time. The SDK is imported into the same Python process as the strategy and directly receives `SIMMER_API_KEY`. Any code in the installed dependency can execute during import or client initialization with the process's environmental and filesystem access. A compromised upstream release, account takeover, dependency confusion caused by index configuration, or an unexpectedly incompatible release could therefore access the credential or alter trade behavior. The audit did not establish that the current `simmer-sdk` package is malicious. The confirmed weakness is the absence of controls that ensure installations receive the reviewed dependency artifact. ### Attack Path 1. The Skill installer resolves `simmer-sdk` without a fixed version or verified hash. 2. A compromised, substituted, or unexpectedly changed release is downloaded from the configured package index. 3. The package executes code during import or `Sim ...[truncated 889 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin `simmer-sdk` to an exact reviewed version. - Use hash-verified installation, such as a requirements file with `--require-hashes`. - Commit a dependency lock file and review dependency changes before updates. - Install only from an explicitly configured, trusted package index. - Verify package provenance and signatures where supported. - Run dependency vulnerability and supply-chain scans in CI. - Use a narrowly scoped, revocable trading credential with strict server-side spending limits. - Isolate the SDK in a restricted runtime with minimal filesystem, environment, and network access. - Avoid exposing unrelated environment variables to the trading process. ]]>
Vulnerability Patterns
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description says 'No API keys required' and frames the skill as reading public Solana/Jupiter signals, but the skill also requires a Simmer API key and can execute authenticated trades. This mismatch can mislead users and automated policy systems about the true capabilities of the skill, increasing the chance of unintended secret exposure or real-money actions under incomplete consent.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The manifest explicitly requires a SIMMER_API_KEY while the skill description claims that no API keys are required. This discrepancy is a supply-chain trust and transparency issue: users may install or run the skill under false assumptions and expose a sensitive credential to code they would not otherwise trust. In an agent/automation context, unnecessary secret collection increases the blast radius if the skill is compromised or behaves unexpectedly.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises network access, environment-variable use, and live trading behavior but does not declare any explicit tool scope or permissions. In an agent ecosystem, missing scope declarations weakens user visibility and policy enforcement, making it easier for a skill to access secrets or external services without clear consent boundaries.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The usage section presents a '--live' command for real trading without a prominent warning about financial loss, irreversible execution, or the need for explicit user confirmation. In a trading skill, this omission increases the risk of accidental live orders and makes the context more dangerous because the documented purpose is market execution, not just analysis.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The module docstring and manifest emphasize that the skill operates from free public Solana/Jupiter data with 'No API keys required.' However, the actual trading path exits unless SIMMER_API_KEY is present and uses SimmerClient to place trades. While market data collection is keyless, the end-to-end skill behavior for live trading is not.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The docstring's usage example implies '--set max_position_usd=50' configures the run. In code, MAX_POSITION_USD, MAX_TRADES_PER_RUN, and SIGNAL_THRESHOLD are initialized at import time from the environment, and the --set handler mutates os.environ only later in __main__. As a result, the current process continues using the old already-cached values, contradicting the advertised behavior.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Live mode can place real trades immediately when invoked with --live, with no secondary confirmation, no interactive acknowledgment, and no explicit high-visibility risk prompt. In a financial-trading skill, that increases the chance of accidental execution from user error, automation misuse, or misunderstood CLI invocation, causing direct monetary loss.

Static analysis

No suspicious patterns detected.