T09 · Insecure Skill Coding Practices
Error
- Location
- trader.py:27
- Finding
- Declared market and portfolio risk controls are missing or weaker at runtime<![CDATA[ ## Vulnerability Details **File Location**: `trader.py:27-35, 183-228, 251-280`; related documentation in `SKILL.md:89-95` **Vulnerability Type**: Missing and inconsistently implemented financial risk controls **Risk Level**: High ### Complete Code Snippet ```python MAX_POSITION = float(os.environ.get("SIMMER_MAX_POSITION", "25")) MIN_VOLUME = float(os.environ.get("SIMMER_MIN_VOLUME", "1000")) MAX_SPREAD = float(os.environ.get("SIMMER_MAX_SPREAD", "0.08")) MIN_DAYS = int(os.environ.get( "SIMMER_MIN_DAYS", "0")) MAX_POSITIONS = int(os.environ.get( "SIMMER_MAX_POSITIONS", "8")) YES_THRESHOLD = float(os.environ.get("SIMMER_YES_THRESHOLD", "0.42")) NO_THRESHOLD = float(os.environ.get("SIMMER_NO_THRESHOLD", "0.58")) MIN_TRADE = float(os.environ.get("SIMMER_MIN_TRADE", "5")) ``` ```python def compute_signal(market) -> tuple[str | None, float, str]: p = market.current_probability q = market.question # Spread gate if market.spread_cents is not None and market.spread_cents / 100 > MAX_SPREAD: return None, 0, f"Spread {market.spread_cents/100:.1%} > {MAX_SPREAD:.1%}" # Days-to-resolution gate if market.resolves_at: try: resolves = datetime.fromisoformat(market.resolves_at.replace("Z", "+00:00")) days = (resolves - datetime.now(timezone.utc)).days if days < MIN_DAYS: return None, 0, f"Only {days} days to resolve" except Exception: pass bias = sport_bias(q) if p <= YES_THRESHOLD: conviction = min(1.0, (YES_THRESHOLD - p) / YES_THRESHOLD * bias) size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2)) edge = YES_THRESHOLD - p return "yes", size, f"YES {p:.0%} edge={edge:.0%} bias={bias:.2f}x size=${size} — {q[:65]}" if p >= NO_THRESHOLD: conviction = min(1.0, (p - NO_THRESHOLD) / (1 - NO_THRESHOLD) * bias) size = max(MIN_TRADE, round(convicti ...[truncated 3424 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Enforce volume before signal generation: ```python volume = getattr(market, "volume", None) if volume is None: return None, 0, "Missing market volume" if volume < MIN_VOLUME: return None, 0, f"Volume ${volume:,.2f} below ${MIN_VOLUME:,.2f}" ``` 2. Align the defaults in `trader.py`, `clawhub.json`, and `SKILL.md` so the documented and effective policies are identical. 3. Query existing open positions before trading and calculate remaining capacity from the actual portfolio: ```python open_positions = client.get_positions(status="open") remaining = MAX_POSITIONS - len(open_positions) ``` 4. Count unique open positions rather than merely successful orders in the current run. 5. Fail closed when required market fields or timestamps cannot be parsed. Log the rejected market and reason rather than silently ignoring parsing errors. 6. Validate all SDK market values for type, range, and presence before making a live-trading decision. 7. Add automated tests covering low volume, missing volume, malformed dates, immediate resolution, existing positions, and repeated invocations. ]]>
