Back to skill

Security audit

Polymarket Longshot Bias Trader

Security checks for vulnerabilities and agentic risk

Overview

This is a clearly described Polymarket trading bot, but its live-trading safeguards do not match its promises and could expose users to larger or riskier trades than expected.

Treat this as a Review item before installing for live use. Paper mode is the safer default, but do not use --live with meaningful funds unless the volume filter, position sizing cap, open-position accounting, and dependency pinning are fixed or enforced by the platform/account outside the skill.

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)

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:58
Finding

Minimum-volume risk control is declared but never enforced

Content
View full analysis
list: """Find active markets via broad keyword sweep, deduplicated.""" seen, unique = set(), [] for kw in KEYWORDS: try: for m in client.find_markets(query=kw): if m.id not in seen: seen.add(m.id) unique.append(m) except Exception as e: print(f"[search] {kw!r}: {e}") return unique ``` The execution loop then evaluates and trades those markets without checking their volume: ```python 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.id) if not ok: print(f" [skip] {why}") continue try: r = client.trade( market_id=m.id, side=side, amount=size, source=TRADE_SOURCE, skill_slug=SKILL_SLUG, reasoning=reasoning, ) ``` ### Technical Analysis `SIMMER_MIN_VOLUME` is documented as a liquidity safeguard, loaded from the environment, exposed as a tunable, and refreshed in `get_client()`. However, it is never referenced by market discovery, signal generation, or trade execution. The configured threshold therefore has no effect. A market can pass the probability, spread, resolution-date, flip-flop, and slippage checks even when its trading volume is below the declared minimum. This is a fail-open implementation of a financial risk control. ### Attack Path 1. ...[truncated 1247 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:190
Finding

Minimum trade size can override the configured maximum position size

Content
View full analysis
= CERTAINTY_THRESHOLD: conviction = min(1.0, (p - CERTAINTY_THRESHOLD) / (1 - CERTAINTY_THRESHOLD) * mult) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) edge = p - CERTAINTY_THRESHOLD return ( "yes", size, f"CERTAINTY-BACK YES p={p:.1%} edge={edge:.1%} mult={mult:.2f}x " f"size=${size} — {q[:65]}" ) ``` The metadata permits contradictory settings: `SIMMER_MAX_POSITION` can be as low as `1`, while `SIMMER_MIN_TRADE` can be as high as `50`. ### Technical Analysis The final size calculation applies only a lower bound: ```python max(MIN_TRADE, calculated_size) ``` It does not apply an upper bound after the minimum is selected. Consequently, whenever `MIN_TRADE > MAX_POSITION`, the resulting order amount exceeds the purported maximum position size. For example, with `MAX_POSITION=1` and `MIN_TRADE=50`, every qualifying signal produces a trade of at least `$50`, even though the configured maximum is `$1`. This violates the safety invariant implied by `MAX_POSITION`. ### Attack Path 1. The environment or management UI supplies `SIMMER_MAX_POSITION=1`. 2. It also supplies `SIMMER_MIN_TRADE=50`, a combination allowed by the independent metadata ranges. 3. The user invokes `python trader.py --live`. 4. A market reaches either probability threshold. 5. `compute_signal()` calculates: ` ...[truncated 779 chars]
Remediation
View remediation
MAX_POSITION: raise ValueError("SIMMER_MIN_TRADE cannot exceed SIMMER_MAX_POSITION") ``` 2. Apply the maximum as the final hard cap: ```python calculated = round(conviction * MAX_POSITION, 2) size = min(MAX_POSITION, max(MIN_TRADE, calculated)) ``` 3. Validate values after `apply_skill_config()` and environment reloading, not only at module import. 4. Add server-side or venue-side order limits so a client defect cannot bypass the maximum. 5. Add boundary tests covering zero conviction, full conviction, equal limits, and `MIN_TRADE > MAX_POSITION`. 6. Consider renaming `MAX_POSITION` to `MAX_ORDER_SIZE` if it is intended to limit each order rather than aggregate exposure. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:288
Finding

Maximum-position control limits only successful orders in the current process

Content
View full analysis
= MAX_POSITIONS: break ``` The counter is incremented only after a successful order: ```python if r.success: placed += 1 ``` ### Technical Analysis `SIMMER_MAX_POSITIONS` is documented as the maximum number of concurrent open positions. The implementation does not query account positions, inspect whether a market already has an open position, or calculate aggregate exposure. Instead, `placed` is initialized to zero every time `run()` executes and counts only successful orders during that process. Repeated invocations can therefore continue placing up to `MAX_POSITIONS` new orders each time, irrespective of positions opened during earlier runs. The limit is effectively a per-run successful-order limit, not a concurrent open-position limit. ### Attack Path 1. Configure `SIMMER_MAX_POSITIONS=10`. 2. Run the trader in live mode; it can place up to ten successful orders. 3. Leave those positions open. 4. Run the trader again manually or through an external automation mechanism. 5. `placed` resets to zero. 6. The second run can submit up to ten additional orders. 7. Repetition continues to increase open-position count and aggregate exposure beyond the configured value. The project itself has `autostart: false` and `cron: null`, so it does not install persistence. Nevertheless, ordinary repeated invocation is sufficient to bypass the intended account-level control. ### Impact Assessment No operating-system privileges are obtained. The affected scope is the trading account and capital accessible to the supplied API key. Potential consequences include: - More concurrent positi ...[truncated 314 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding

Security-critical trading SDK is installed without version or integrity pinning

Content
View full analysis
Remediation
View remediation
" ] ``` 2. Use a lockfile with cryptographic hashes or an installation mode equivalent to `pip --require-hashes`. 3. Verify package provenance, maintainer identity, release signatures, and source repository tags. 4. Run dependency vulnerability and supply-chain scans in continuous integration. 5. Review dependency changes before updating the pinned version. 6. Restrict `SIMMER_API_KEY` to the minimum required permissions and enforce server-side trade limits. 7. Run the skill in an isolated environment with minimal filesystem access and restricted outbound networking where operationally feasible. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill description advertises domain-agnostic exploitation across 'every market category' and positions the skill as broadly applicable without clear activation constraints. In an agentic environment, this can cause the skill to be selected for loosely related finance, betting, or market-analysis prompts, leading to unintended trade discovery or execution workflows outside a narrowly intended scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest explicitly requires an API key and configures an automated trading entrypoint, but provides no user-facing disclosure that the skill will access sensitive credentials and may place trades autonomously. In a trading context, this increases the risk of users granting powerful market access without informed consent, which can lead to financial loss if the strategy is unsafe, misconfigured, or abused.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The market discovery step instructs a broad keyword sweep across many high-liquidity categories with no category, user-intent, or query-scoping limits. While not malicious by itself, this increases the chance that an agent over-collects markets or acts on weakly related requests, expanding operational scope and potentially triggering unwanted trading behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.