Back to skill

Security audit

Polymarket 24h Cross Asset Sync Trader

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed trading bot, but its live-trading safeguards and signal logic do not fully match what it tells users.

Use paper mode only unless you have independently reviewed the strategy, fixed the probability and risk-limit issues, scoped the SIMMER_API_KEY as tightly as possible, set external account limits, and pinned or otherwise controlled the simmer-sdk dependency. Treat --live as permission for automated 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:146
Finding
Incorrect Probability Normalization Can Trigger Invalid Live Trades<![CDATA[ ## Vulnerability Details **File Location**: `trader.py:146-148`, `trader.py:193-194`, and live execution at `trader.py:434-457` **Vulnerability Type**: Incorrect security-critical trading logic **Risk Level**: High ### Vulnerable Code ```python direction = infer_direction(q, p) # Normalize to "up probability" for comparison across assets up_prob = p if direction == "up" or p >= 0.50 else 1.0 - p ``` ```python up_probs = [e.up_probability for e in entries] mean_up = statistics.mean(up_probs) ``` ```python consensus_dir = "up" if mean_up >= 0.50 else "down" ``` The resulting signal can reach the live trading operation: ```python r = client.trade( market_id=market_id, side=side, amount=size, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, reasoning=reasoning, ) ``` ### Technical Analysis `infer_direction()` returns `"down"` when the market probability is below 0.50. The subsequent normalization then converts that probability to `1.0 - p`. Therefore, a 45% probability for Up becomes an `up_probability` of 55%, even though the documented strategy requires it to remain 45%. As a result, every normalized value is at least 0.50. The calculated group mean consequently cannot represent a genuine Down consensus, making the Down-consensus branch effectively unreachable and potentially manufacturing false Up divergences. This behavior also contradicts the documented example, in which a market at 45% Up must be compared directly with other assets at 54%–58% Up. ### Attack Path 1. The skill discovers an eligible market whose YES probability is below 50%. 2. `infer_direction()` labels the market as Down. 3. The normalization logic changes its Up probability from `p` to `1-p`. 4. The inflated value contributes to an artificial Up consensus. 5. `find_divergences()` generates a potentially incorrect trade opportunity. 6. If the probability and context gates pass, an operator running the skill with `--live` causes `client.trade()` to submit ...[truncated 687 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Determine which market outcome token represents “Up” using structured outcome metadata rather than deriving outcome identity from the current probability. - Preserve the actual probability of the Up outcome. If YES represents Up, use `up_prob = p`; if NO represents Up, use `up_prob = 1.0 - p`. - Reject markets when outcome ordering cannot be verified reliably. - Add unit tests covering: - Mixed values such as 58%, 56%, 54%, and 45%. - Groups in which every asset favors Down. - Markets with reversed outcome ordering. - Values exactly at 50%. - Both YES and NO trade generation. - Add a live-mode preflight check that logs the verified outcome mapping and calculated consensus before an order is submitted. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:40
Finding
Documented Volume and Concurrent Position Limits Are Not Enforced<![CDATA[ ## Vulnerability Details **File Location**: `trader.py:40-47`, `trader.py:268-286`, and `trader.py:416-418` **Vulnerability Type**: Missing enforcement of financial risk controls **Risk Level**: Medium ### Vulnerable Code The limits are loaded from configuration: ```python MAX_POSITION = float(os.environ.get("SIMMER_MAX_POSITION", "40")) MIN_VOLUME = float(os.environ.get("SIMMER_MIN_VOLUME", "5000")) MAX_SPREAD = float(os.environ.get("SIMMER_MAX_SPREAD", "0.08")) MIN_DAYS = int(os.environ.get( "SIMMER_MIN_DAYS", "0")) MAX_POSITIONS = int(os.environ.get( "SIMMER_MAX_POSITIONS", "8")) 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")) ``` However, market validation checks probability, spread, and resolution time without enforcing `MIN_VOLUME`: ```python def valid_market(market) -> tuple[bool, str]: """Check spread and days-to-resolution 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" ``` The position limit only counts successful orders in the current invocation: ```python placed = 0 for market_id, opp in sorted(all_opps.items(), key=lambda ...[truncated 1795 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Obtain verified market volume from a structured SDK field and reject markets whose volume is missing, malformed, or below `MIN_VOLUME`. - Define whether the volume requirement applies to total volume, recent volume, or executable liquidity and document that definition. - Query the account’s current open positions before submitting any order. - Enforce the limit against `existing_open_positions + successful_orders_in_this_run`. - Reserve capacity atomically when concurrent skill instances may execute. - Add a portfolio-level exposure cap in addition to a position-count cap. - Fail closed if the SDK cannot retrieve positions or required market-liquidity data in live mode. - Add tests for repeated invocations, pre-existing positions, low-volume markets, and concurrent execution. ]]>

T08 · Insecure Dependencies

Note
Location
clawhub.json:3
Finding
High-Privilege Trading Dependency Is Not Version-Pinned<![CDATA[ ## Vulnerability Details **File Location**: `clawhub.json:3-9` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Code ```json { "requires": { "env": [ "SIMMER_API_KEY" ], "pip": [ "simmer-sdk" ] } } ``` ### 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 is security-sensitive because it receives `SIMMER_API_KEY`, performs network requests, discovers markets, and submits trades. A compromised upstream release, maintainer account, or package distribution channel could cause unreviewed code to execute with the skill process’s permissions and trading credentials. The audit found no evidence that the currently referenced package is malicious. The issue is the absence of controls preventing a future package release from silently changing the effective code. ### Attack Path 1. An attacker compromises the package publisher, release pipeline, or package distribution channel. 2. The attacker publishes a malicious or backdoored version of `simmer-sdk`. 3. A new installation resolves the unpinned dependency to that version. 4. `trader.py` imports `SimmerClient` from the compromised package. 5. The application passes `SIMMER_API_KEY` to the dependency and invokes its market and trading methods. 6. Malicious package code can misuse the credential, alter orders, or perform other actions available to the Python process. ### Impact Assessment A compromised dependency would execute with the same local privileges as the skill process. It could access environment variables available to that process, including `SIMMER_API_KEY`, and could misuse the associated trading authority. Depending on the runtime sandbox and credential permissions, impact could include credential disclosure, manipulated trades, unauthorized account activ ...[truncated 114 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin `simmer-sdk` to an exact, reviewed version. - Use a lockfile with cryptographic hashes, or install with hash verification enabled. - Review release provenance, maintainer identity, and package repository links before upgrades. - Perform dependency vulnerability and provenance scanning in CI. - Test upgrades in an isolated environment before deployment. - Restrict the skill process to the minimum filesystem and network permissions required. - Scope `SIMMER_API_KEY` to the minimum necessary trading permissions and apply account-level spending limits where supported. ]]>
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)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill references a high-value environment credential (`SIMMER_API_KEY`) and describes live trading capability, but it does not declare explicit tool scope or permissions boundaries. In an agent ecosystem, missing scope declarations can allow broader-than-expected access to environment data or execution surfaces, increasing the chance of credential exposure or misuse if the skill is invoked by a permissive runtime.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
This markdown file describes a trading skill that can place live trades when run with `--live`, but the warning is limited to 'Real USDC' and does not explicitly disclose risks such as financial loss from automated execution or strategy error. For markdown files, safety-impacting behavior that can affect user assets should include clear user-facing warnings.

Static analysis

No suspicious patterns detected.