Back to skill

Security audit

Polymarket Nordic Trader

Security checks for vulnerabilities and agentic risk

Overview

The skill is openly a Polymarket trading automaton, but its live-trading safeguards have concrete gaps users should review before trusting it with funds.

Install only if you understand it can submit real Polymarket orders when run with --live. Use paper mode first, use a dedicated least-privilege Simmer/Polymarket credential, avoid live-capable keys in automation, pin and review simmer-sdk, and fix or account for the missing volume gate and max-position sizing issue before risking funds.

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)

T08 · Insecure Dependencies

Warning
Location
clawhub.json:7
Finding

Unpinned Trading SDK Creates a Supply-Chain Risk

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:160
Finding

Minimum Trade Floor Can Exceed the Configured Maximum Position

Content
View full analysis
= NO_THRESHOLD: conviction = min(1.0, (p - NO_THRESHOLD) / (1 - NO_THRESHOLD) * bias) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) edge = p - NO_THRESHOLD return "no", size, f"NO YES={p:.0%} edge={edge:.0%} bias={bias:.2f}x size=${size} — {q[:65]}" ``` ### Technical Analysis The code documents `MAX_POSITION` as a maximum position size, but computes the final amount with: ```python max(MIN_TRADE, calculated_size) ``` The supported UI range allows `SIMMER_MAX_POSITION=1`, while `SIMMER_MIN_TRADE` defaults to `5`. Under that configuration, every qualifying signal produces an order of at least `$5`, even though the operator configured a `$1` maximum. The same issue occurs whenever `MIN_TRADE` is greater than `MAX_POSITION`, whether through the supported maximum-position control or direct environment configuration. The calculation limits conviction to `1.0`, but that does not protect the cap after the minimum floor is applied. ### Attack Path 1. An operator sets `SIMMER_M ...[truncated 1140 chars]
Remediation
View remediation
MAX_POSITION: raise ValueError("SIMMER_MIN_TRADE must not exceed SIMMER_MAX_POSITION") ``` 2. Apply both lower and upper bounds to the final order amount: ```python size = min( MAX_POSITION, max(MIN_TRADE, round(conviction * MAX_POSITION, 2)), ) ``` 3. Adjust the declared configuration ranges so the UI cannot select an unsupported combination. 4. Add unit tests for `MAX_POSITION < MIN_TRADE`, equality at the boundary, zero conviction, and full conviction. 5. Log the effective risk parameters after `apply_skill_config()` and before any live order. 6. Fail closed in live mode if any risk parameter is negative, non-finite, contradictory, or outside an approved range. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:201
Finding

Declared Minimum Market Volume Safeguard Is Not Enforced

Content
View full analysis
= 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, ) tag = "(sim)" if r.simulated else "(live)" status = "OK" if r.success else f"FAIL:{r.error}" print(f" [trade] {side.upper()} ${size} {tag} {status} — {reasoning[:70]}") if r.success: placed += 1 except Exception as e: print(f" [error] {m.id}: {e}") ``` ### Technical Analysis `MIN_VOLUME` is loaded from the environment, can be configured through `clawhub.json`, and is described as a risk parameter in the documentation. Nevertheless, neither `find_markets()`, `compute_signal()`, nor the trading loop checks a market's volume before calling `client.trade()`. The implemented spread and context checks do not replace a volume check. A market can temporarily display an acceptable quoted spread while still having insufficient depth or overall liquidity. Low-volume markets may be easier to manipulate and more difficult to exit without substantial price impact. If the SDK's market model does not expose reliable volume data, the code ...[truncated 1435 chars]
Remediation
View remediation
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 (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill references environment-based credentials (SIMMER_API_KEY) and describes executable trading behavior, but it does not declare an explicit tool/permission scope such as allowed tools or environment access. That makes the skill's effective capabilities less transparent to reviewers and increases the risk of over-privileged execution if the runtime exposes broader env access than intended.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 112)May include surrounding context.

md
## Key Data Sources

- **SMHI** (Weather): https://www.smhi.se/
- **Riksdagen** (Parliament): https://data.riksdagen.se/
- **SCB** (Statistics): https://www.scb.se/
- **SVT Nyheter**: https://www.svt.se/nyheter/
- **Di.se** (Business): https://www.di.se/

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest requires a sensitive credential (SIMMER_API_KEY) but provides no user-facing disclosure of what service it authenticates to, what permissions it grants, or how it will be used by the trading agent. In a financial trading skill, undisclosed credential use is more concerning because the key may enable account actions, market access, or fund movement, leaving users unable to make an informed trust decision.

Content

No source excerpt is available for this finding.