Back to skill

Security audit

Candle Doji Breakout Trader

Security checks for vulnerabilities and agentic risk

Overview

The skill is not deceptive, but it should be reviewed carefully because it can place real trades and some advertised risk controls are weak or not enforced.

Use this first in paper mode. Before any --live use, review or fix the risk-control gaps, pin and verify simmer-sdk, and use a narrowly scoped API key with only the trading authority you are willing to expose.

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 (5)

T08 · Insecure Dependencies

Warning
Location
clawhub.json:2
Finding

Unpinned Third-Party Trading SDK Creates a Supply-Chain Risk

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:285
Finding

Live-Trading Context Safeguards Fail Open on Errors

Content
View full analysis
0.15: return False, f"Slippage {slip['slippage_pct']:.1%}" for w in ctx.get("warnings", []): safe_print(f" [warn] {w}") except Exception as e: safe_print(f" [ctx] {market_id}: {e}") return True, "ok" ``` The returned approval is used before order submission in `trader.py:330-342`: ```python ok, why = context_ok(client, m.id) if not ok: safe_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 `context_ok()` is intended to reject trades involving recent directional reversals or excessive slippage. However, it returns approval when: - `get_market_context()` returns no context; - the SDK raises a network, parsing, authentication, or runtime exception; - the context object has an unexpected type or schema; - values used by the function trigger conversion or formatting errors. The exception handler only logs the error. Execution then reaches `return True, "ok"`, allowing the order to proceed. This changes the safety control from a mandatory precondition into a best-effort advisory check. The behavior affects both simulated and live modes. Its material security and financial impact is greatest when `--live` selects the Polymarket venue. ### Attack ...[truncated 1265 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:226
Finding

Invalid Resolution Timestamps Bypass the Minimum-Time Safety Gate

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:320
Finding

Configured Liquidity and Concurrent-Position Limits Are Not Enforced

Content
View full analysis
= MAX_POSITIONS: break side, size, reasoning = compute_signal(m, trend_dir) ``` The liquidity threshold is declared in `clawhub.json`: ```json { "env": "SIMMER_MIN_VOLUME", "type": "number", "default": 3000, "range": [0, 500000], "step": 500, "label": "Min market volume USD" }, { "env": "SIMMER_MAX_POSITIONS", "type": "number", "default": 10, "range": [1, 20], "step": 1, "label": "Max open positions" } ``` No code in the reviewed project compares a market's volume against `MIN_VOLUME`. In addition, no code queries existing open positions before applying `MAX_POSITIONS`. ### Technical Analysis `MIN_VOLUME` is configured and reloaded after applying the Skill configuration, but it is never used as a market eligibility condition. As a result, markets below the documented liquidity floor can be traded. `MAX_POSITIONS` is documented as limiting concurrent open positions. In practice, `placed` begins at zero every time the program runs and counts only successful orders submitted during that invocation. Existing positions and orders placed by previous runs are not included. This creates a disc ...[truncated 1462 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:244
Finding

Minimum Trade Size Can Override the Maximum Position Limit

Content
View full analysis
= NO_THRESHOLD: conviction = (p - NO_THRESHOLD) / (1 - NO_THRESHOLD) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) ``` The configuration permits the minimum trade to exceed the maximum position. For example, `clawhub.json` allows `SIMMER_MAX_POSITION` as low as `1` and `SIMMER_MIN_TRADE` as high as `50`. ### Technical Analysis The final order size is selected with `max(MIN_TRADE, calculated_size)`. This guarantees the minimum trade floor but does not enforce the maximum position ceiling. Because the two settings are independently configurable, a valid metadata configuration can set `MIN_TRADE > MAX_POSITION`. In that state, every qualifying trade is sized to at least `MIN_TRADE`, directly exceeding the configured maximum. Even when the parameters are normally configured, the application performs no startup validation for cross-field constraints. Configuration changes applied through `_client.apply_skill_config(SKILL_SLUG)` are also accepted without checking that the resulting combination is safe. ### Attack Path 1. The Skill receives a configuration in which `SIMMER_MIN_TRADE` is greater than `SIMMER_MAX_POSITION`; for example, a minimum trade of 50 and maximum position of 1. 2. Market discovery identifies a qualifying breakout opportunity. 3. `compute_signal()` calculates conviction-based size at or below `MAX_POSITION`. 4. `max(MIN_TRADE, calculated_size)` selects the larger minimum trade value. 5. `run()` submits an order whose amount exceeds the configured p ...[truncated 717 chars]
Remediation
View remediation
MAX_POSITION: raise ValueError("SIMMER_MIN_TRADE must not exceed SIMMER_MAX_POSITION") ``` 2. Explicitly enforce the ceiling in final sizing logic: ```python calculated = round(conviction * MAX_POSITION, 2) size = min(MAX_POSITION, max(MIN_TRADE, calculated)) ``` 3. Reject rather than silently clamp contradictory configurations when running live, so the operator is made aware of the policy error. 4. Add finite-number validation to reject `NaN` and infinity values supplied through the environment. 5. Validate threshold relationships and ranges, including nonzero denominators for conviction calculations. 6. Add tests for minimum-equals-maximum, minimum-greater-than-maximum, zero and negative values, boundary probabilities, and configuration changes applied by the SDK. ]]>
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)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill references a high-value secret (SIMMER_API_KEY) and describes trading behavior, but it does not declare any explicit tool scope or permissions boundary. When a skill can access environment variables without a restrictive manifest, an agent runtime may overgrant access to secrets or capabilities beyond what the skill actually needs, increasing the blast radius if the skill is modified, misused, or compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This manifest requires the SIMMER_API_KEY environment variable, which indicates the skill uses sensitive credentials. In this file there is no accompanying warning, description, or user-facing disclosure about credential use, and manifest files are in scope for missing-warning review when they are markdown only? However this file itself exposes the requirement semantically without any visible warning to the user about credential handling or external service access.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.