T09 · Insecure Skill Coding Practices
Error
- Location
- trader.py:49
- Finding
- Cached Live Client Can Bypass Requested Paper-Trading Mode<![CDATA[ ## Vulnerability Details **File Location**: `trader.py`, lines 49-64 **Vulnerability Type**: Execution-mode confusion caused by unsafe global client caching **Risk Level**: High ### Vulnerable Code ```python _client: SimmerClient | None = None def safe_print(text): """Print with fallback for non-ASCII characters (Windows cp1252 terminals).""" try: print(text) except UnicodeEncodeError: print(text.encode('ascii', 'replace').decode()) def get_client(live: bool = False) -> SimmerClient: """ live=False -> venue="sim" (paper trades -- safe default). live=True -> venue="polymarket" (real trades, only with --live flag). """ global _client, MAX_POSITION, MIN_VOLUME, MAX_SPREAD, MIN_DAYS, MAX_POSITIONS global YES_THRESHOLD, NO_THRESHOLD, MIN_TRADE, STREAK_LENGTH if _client is None: venue = "polymarket" if live else "sim" _client = SimmerClient( api_key=os.environ["SIMMER_API_KEY"], venue=venue, ) if live: _client.live = True ``` ### Technical Analysis The module stores one `SimmerClient` in the global `_client` variable. The selected venue and live-trading state are established only when `_client` is `None`. Subsequent calls return the existing client without checking whether its venue matches the newly requested `live` argument. Consequently, after the client has been initialized with `live=True`, a later call to `get_client(live=False)` or `run(live=False)` in the same Python process reuses the live Polymarket client. The second execution may print that it is in paper mode while still submitting orders through a client configured for real trading. This is especially relevant in managed runtimes, notebooks, test processes, or embedding applications where the module can remain loaded and `run()` can be invoked more than once. ### Attack Path 1. A process imports `trader.py`. 2. The process invokes `run(live=True)` or `get_cli ...[truncated 837 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not share one mutable client across live and simulated modes. - Maintain separate clients keyed by venue, such as `{"sim": ..., "polymarket": ...}`, or instantiate a new client for every run. - If caching is required, store the configured mode alongside the client and recreate the client whenever the requested mode differs. - Before each trade, verify that the client's authoritative venue and live state match the current invocation. - Fail closed if the SDK does not expose a verifiable execution mode. - Add a regression test that initializes live mode first and then invokes paper mode in the same process, confirming that the second trade is simulated. ]]>
