T09 · Insecure Skill Coding Practices
Warning
- Location
- trader.py:347
- Finding
- Documented live-trading risk controls are not fully enforced<![CDATA[ ## Vulnerability Details **File Location**: `trader.py:35-38`, `trader.py:347-369`, `trader.py:551-580`; related claims in `SKILL.md:101-104` **Vulnerability Type**: Missing enforcement of financial risk controls **Risk Level**: Medium ### Vulnerable Code ```python MIN_VOLUME = float(os.environ.get("SIMMER_MIN_VOLUME", "5000")) 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")) ``` ```python def valid_market(market) -> tuple[bool, str]: """Check spread and days-to-resolution 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" ``` ```python placed = 0 for market_id, opp in sorted(all_opps.items(), key=lambda x: -x[1][2]): if placed >= MAX_POSITIONS: break market, side_hint, violation, reason = opp side, size, reasoning = compute_signal(market, side_hint, violation, reason) if not side: print(f" [skip] {reasoning}") continue ok, why = context_ok(client, market_id) if not ok: print(f" [skip] {why}") continue try: r = client.trade( market_id=market_id, side=side, amount=s ...[truncated 2733 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Enforce the volume threshold before signal generation: ```python volume = getattr(market, "volume", None) if not isinstance(volume, (int, float)): return False, "missing market volume" if float(volume) < MIN_VOLUME: return False, f"Volume ${volume:,.2f} < ${MIN_VOLUME:,.2f}" ``` 2. Confirm the exact volume field and units exposed by `simmer-sdk`. Do not silently accept missing or malformed volume data in live mode. 3. Query the account's existing open positions before placing orders: ```python open_positions = client.get_positions(status="open") remaining_slots = max(0, MAX_POSITIONS - len(open_positions)) ``` 4. Stop trading when `remaining_slots` reaches zero, and decrement it only after a confirmed successful order. 5. Deduplicate exposure by market so repeated executions cannot unintentionally stack the same position unless explicitly permitted. 6. Distinguish between: - Maximum orders per run. - Maximum concurrent open positions. - Maximum aggregate portfolio exposure. 7. Fail closed in live mode if portfolio state, volume, spread, or resolution data cannot be retrieved reliably. 8. Add automated tests covering low-volume rejection, missing-volume rejection, existing-position accounting, repeated invocations, and concurrent execution. ]]>
