Back to skill

Security audit

Polymarket Macro Event Cascade Trader

Security checks for vulnerabilities and agentic risk

Overview

This skill is not deceptive, but it should be reviewed carefully because it can place real prediction-market trades and several promised risk limits are not fully enforced.

Install only if you are comfortable giving this skill trading authority. Keep it in paper mode until you have reviewed the risk-limit behavior, use the smallest possible funded account and API permissions, pin or review the SDK dependency, and do not rely on the advertised volume or concurrent-position safeguards as complete account-level controls.

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

Warning
Location
trader.py:218
Finding

Minimum Market Volume Safeguard Is Declared but Never Enforced

Content
View full analysis
tuple[bool, str]: """Standard 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, loaded into the application, and displayed at runtime. Nevertheless, neither `valid_market()` nor `compute_signal()` reads a market-volume field or compares it with `MIN_VOLUME`. This discrepancy creates a false security expectation. A market can pass all implemented checks even if it has negligible liquidity. The spread check is not an adequate substitute for a volume or liquidity chec ...[truncated 1069 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:268
Finding

Minimum Trade Configuration Can Bypass the Maximum Per-Trade Position Limit

Content
View full analysis
= NO_THRESHOLD: conviction = (p - NO_THRESHOLD) / (1 - NO_THRESHOLD) conviction = min(1.0, conviction + lag) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) ``` ### Technical Analysis The order amount is calculated with `max(MIN_TRADE, conviction * MAX_POSITION)`. This guarantees the minimum trade size but does not guarantee that the result remains at or below `MAX_POSITION`. The metadata permits `SIMMER_MAX_POSITION` values as low as 1 and `SIMMER_MIN_TRADE` values as high as 100. Therefore, supported configuration values can produce `MIN_TRADE > MAX_POSITION`, causing the supposed maximum position limit to be exceeded. ### Attack Path 1. The runtime environment or managed skill configuration sets `SIMMER_MAX_POSITION` to a value lower than `SIMMER_MIN_TRADE`. 2. A market satisfies the cascade and threshold checks. 3. `compute_signal()` evaluates `max(MIN_TRADE, conviction * MAX_POSITION)`. 4. The resulting amount equals `MIN_TRADE`, even though that amount exceeds `MAX_POSITION`. 5. In live mode, the oversized amount is passed directly to `client.trade()`. ### Impact Assessment This issue does not grant operating-system privileges. It bypasses an application-level financial control and can expose the authorized trading account to a larger per-order commitment than the operator configured. The maxim ...[truncated 138 chars]
Remediation
View remediation
MAX_POSITION`. 2. Bound the final amount explicitly: ```python raw_size = round(conviction * MAX_POSITION, 2) size = min(MAX_POSITION, max(MIN_TRADE, raw_size)) ``` 3. Validate that all monetary settings are finite, positive, and within supported venue limits. 4. Align the `clawhub.json` ranges so they cannot produce contradictory settings. 5. Add a final invariant immediately before `client.trade()` that rejects any amount greater than `MAX_POSITION`. 6. Add tests for boundary and contradictory configurations, including `MIN_TRADE == MAX_POSITION` and `MIN_TRADE > MAX_POSITION`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:442
Finding

Maximum Concurrent Position Setting Only Limits Orders Within the Current Run

Content
View full analysis
= MAX_POSITIONS: break side, size, reasoning = compute_signal(target_market, trade_side, lag) ``` After a successful order, only the local counter is incremented: ```python if r.success: placed += 1 ``` ### Technical Analysis `MAX_POSITIONS` is documented as the maximum number of concurrent open positions. The implementation instead counts successful orders placed during one invocation. It does not obtain the account's existing open positions before trading and does not determine whether a new order increases an existing position. Because `placed` is reset to zero whenever `run()` starts, repeated manual, scheduled, or managed invocations can cumulatively exceed the documented concurrent-position limit. ### Attack Path 1. The account already has open positions from a prior invocation. 2. The skill is invoked again while those positions remain open. 3. The local `placed` variable starts at zero. 4. The skill submits up to `MAX_POSITIONS` additional successful orders without accounting for existing exposure. 5. Repeated invocations continue increasing the number of open positions beyond the configured limit. ### Impact Assessment No host-level privilege is obtained. The affected privilege is the skill's legitimate authority to place trades through `SIMMER_API_KEY`. The flaw can cause account-wide exposure to exceed the operator's intended concurrent-position cap, increasing aggregate financial loss and concentration risk. Actual impact remains subject to account balance, venue rules, and any independent SDK controls. ]]>
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
clawhub.json:3
Finding

Privileged Trading SDK Dependency Is Not Version-Pinned

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill declares a high-value credential requirement (SIMMER_API_KEY) and implies environment variable access, but it does not define any explicit tool scope or allowed-tools policy. In an agent platform, this can lead to overbroad runtime access to secrets or other environment data beyond what the skill actually needs, increasing the blast radius if the skill or its dependencies behave unexpectedly.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.