Back to skill

Security audit

Polymarket Weather Bucket Thresholds

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed automated trading skill, but its controls are too loose for account-level trading actions.

Review this before installing or enabling live mode. It should be tightened so exits only affect positions opened by this skill, strict warnings block any warning, entry spend and total trades are hard capped, and the unused unpinned dependency is removed or pinned.

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
trade.py:140
Finding

Unscoped Exit Logic Can Liquidate Unrelated YES Positions

Content
View full analysis
0 and prob is not None and prob >= EXIT_THRESHOLD: ctx = get_context(mid) if args.strict_warnings and has_blocking_warnings(ctx): print(f"Skip EXIT due to warnings: {mid} warnings={ctx.get('warnings')}") continue reasoning = f"Exit: prob {prob:.0%} >= {EXIT_THRESHOLD:.0%}. Selling entire YES position." res = trade( mid, "yes", action="sell", venue="sim", shares=shares_yes, reasoning=reasoning, live=live, ) print("EXIT result:", res) exits_done += 1 ``` ### Technical Analysis The exit pass retrieves all simulation positions associated with the authenticated account and considers every positive YES position eligible for liquidation once its probability reaches 45%. Unlike the entry pass, the exit logic does not: - Confirm that the associated market is related to weather or temperature. - Confirm that the position was opened by this skill. - Check the position's `source` or `skill_slug`. - Maintain a local allowlist of market IDs opened by the strategy. Consequently, the skill's authority is broader than its documented weather-market strategy. The trade payload sells the full `shares_yes` balance, so an unrelated qualifying position can be liquidated completely. ### Att ...[truncated 914 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trade.py:104
Finding

Documented Warning, Spending, and Trade-Count Safeguards Are Not Fully Enforced

Content
View full analysis
= 0.45 - Max entry spend: ~$2 (default uses 1.80 to avoid slippage overshoot) - Max trades per scan: 5 - Schedule: every 2 minutes - Safeguards: strict — skip any market with context warnings - Dry-run by default. Use `--live` to place trades. ``` Warning handling blocks only three phrases: ```python def has_blocking_warnings(ctx: dict) -> bool: w = ctx.get("warnings") or [] if isinstance(w, dict): w = list(w.values()) if not w: return False text = " | ".join(map(str, w)).lower() blocking = ["high urgency", "wide spread", "elevated risk"] return any(b in text for b in blocking) ``` User-provided limits are accepted without safe upper-bound validation: ```python ap.add_argument("--live", action="store_true", help="Place real trades (default: dry-run)") ap.add_argument("--max-trades", type=int, default=MAX_TRADES_PER_SCAN) ap.add_argument("--entry-amount", type=float, default=DEFAULT_ENTRY_AMOUNT) ``` The trade-count limit applies only to entries: ```python for m in candidates: if trades_done >= args.max_trades: break ``` The unrestricted entry amount is sent directly to the trading function: ```python res = trade( mid, "yes", action="buy", venue="sim", amount=args.entry_amount, reasoning=reasoning, live=live, ) ``` ### Technical Analysis The implementation does not enforce several controls promised by the skill documentation: 1. **Incomplete strict-warning handling:** Strict mode is documented as skipping a market when any context warning exists. ...[truncated 2266 chars]
Remediation
View remediation
bool: warnings = ctx.get("warnings") return bool(warnings) ``` 2. Validate numeric arguments immediately after parsing: ```python if not 0 < args.entry_amount <= 2.0: ap.error("--entry-amount must be greater than 0 and no more than 2.0") if not 0 <= args.max_trades <= MAX_TRADES_PER_SCAN: ap.error(f"--max-trades must be between 0 and {MAX_TRADES_PER_SCAN}") ``` 3. Reject non-finite values such as `NaN` and infinity with `math.isfinite()`. 4. Use one shared trade counter for entries and exits, incrementing it only after a successful trade response. 5. Stop both passes once the combined maximum of five trades is reached. 6. If exits must take priority over entries, document that policy while retaining an explicit global safety ceiling. 7. Add automated tests for unknown warning text, oversized and non-finite amounts, excessive `--max-trades` values, and combined entry/exit counts. ]]>

T08 · Insecure Dependencies

Warning
Location
clawhub.json:2
Finding

Unused Dependency Is Unpinned and Introduces Avoidable Supply-Chain Exposure

Content
View full analysis
Remediation
View remediation
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 (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding

The skill advertises behavior that depends on external execution capabilities like networking and likely environment access, but it does not declare any explicit tool scope or permissions. This creates an authorization and review gap: an agent runtime may grant broader capabilities than intended, making it harder to enforce least privilege and increasing the chance of unauthorized outbound requests, secret exposure, or unintended trading actions.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The implementation scope does not match the stated strategy: despite being described as a global temperature bucket threshold strategy, the market filter also admits precipitation, rain, and snow markets. This creates strategy drift and can cause the agent to trade instruments outside the user's intended risk model, making behavior less predictable and potentially violating user expectations or guardrails.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The CLI help text says '--live' will 'Place real trades', but the actual trade calls in both entry and exit paths hardcode venue='sim'. This is an active contradiction between the inline documentation and runtime behavior, which could mislead operators about whether live capital is at risk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.