Back to skill

Security audit

Trading

Security checks for vulnerabilities and agentic risk

Overview

This trading skill is mostly coherent, but its advertised dry run can still make an authenticated remote Simmer market-import/share request before stopping short of a trade.

Review this carefully before installing. Only use it with a Simmer API key you are willing to grant trading-related account access to, do not assume dry-run is side-effect free, and run it in a controlled Python environment without untrusted tradejournal modules on the import path. Treat any cron or heartbeat setup as live automated trading and set strict position limits.

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

T09 · Insecure Skill Coding Practices

Warning
Location
fastloop_trader.py:632
Finding
Dry-run mode performs an authenticated remote market import## Vulnerability Details **File Location**: `fastloop_trader.py:364-370` and `fastloop_trader.py:632-641` **Vulnerability Type**: Dry-run side effect and unnecessary credential use **Risk Level**: Medium ### Vulnerable Code ```python def import_fast_market_market(api_key, slug): """Import a fast market to Simmer. Returns market_id or None.""" url = f"https://polymarket.com/event/{slug}" result = simmer_request("/api/sdk/markets/import", method="POST", data={ "polymarket_url": url, "shared": True, }, api_key=api_key) ``` ```python # Step 5: Import & Trade log(f"\n🔗 Importing to Simmer...", force=True) market_id, import_error = import_fast_market_market(api_key, best["slug"]) if not market_id: log(f" ❌ Import failed: {import_error}", force=True) return log(f" ✅ Market ID: {market_id[:16]}...", force=True) if dry_run: est_shares = position_size / price if price > 0 else 0 log(f" [DRY RUN] Would buy {side.upper()} ${position_size:.2f} (~{est_shares:.1f} shares)", force=True) ``` ### Technical Analysis The market-import operation is executed before the `dry_run` condition is evaluated. The import is an authenticated HTTP `POST` to the Simmer API and explicitly includes `"shared": True`. Consequently, default dry-run execution is not side-effect free. When the strategy identifies a qualifying signal, it can create or share remote market state and consume account import quota even though no trade is submitted. This conflicts with the documented expectation that dry-run mode only reports what would happen. The behavior also exceeds minimum privilege for simulation: local market analysis and trade estimation do not require an authenticated import or the use of `SIMMER_API_KEY`. ### Attack Path 1. A user follows the documented default invocation and runs the script without `--live`. 2. The script loads `SIMMER_API_KEY` and discovers a qual ...[truncated 1022 chars]
Remediation
## Remediation Suggestions - Move the dry-run branch before `import_fast_market_market()` so simulation performs no authenticated mutation. - Calculate estimated position size and shares using discovered public market data, then return before any import or trade request. - Delay `get_api_key()` until an operation genuinely requires authentication. Public-data dry runs should work without `SIMMER_API_KEY`. - If dry-run import testing is necessary, add a separate explicit option such as `--test-import`, clearly document its remote effects, and default `"shared"` to `False`. - Add automated tests that assert dry-run mode never invokes authenticated `POST`, `PUT`, `PATCH`, or `DELETE` requests. - Document exactly which commands can mutate remote account state.

T08 · Insecure Dependencies

Warning
Location
fastloop_trader.py:27
Finding
Automatic import of an undeclared ambient trade-journal module enables dependency shadowing## Vulnerability Details **File Location**: `fastloop_trader.py:27-39` **Vulnerability Type**: Unpinned optional dependency loaded from the ambient Python import path **Risk Level**: Medium ### Vulnerable Code ```python # Optional: Trade Journal integration try: from tradejournal import log_trade JOURNAL_AVAILABLE = True except ImportError: try: from skills.tradejournal import log_trade JOURNAL_AVAILABLE = True except ImportError: JOURNAL_AVAILABLE = False def log_trade(*args, **kwargs): pass ``` ### Technical Analysis The script automatically imports `tradejournal` or `skills.tradejournal` without declaring, pinning, or validating the dependency. Python resolves these names through `sys.path`, which commonly includes the script directory, current environment, installed packages, and paths supplied through `PYTHONPATH`. Importing a Python module executes its top-level code immediately. Therefore, a malicious file or package that shadows either expected module name can run arbitrary code as soon as the trader starts. This can occur even in dry-run mode because the import takes place before command-line processing and strategy execution. The integration is optional but automatically enabled whenever a matching module can be resolved. This violates least-surprise and supply-chain hardening principles because the script neither requires explicit operator consent nor verifies that the imported module is the intended implementation. ### Attack Path 1. An attacker gains the ability to place a file named `tradejournal.py`, create a `skills/tradejournal.py` package path, modify `PYTHONPATH`, or install a malicious package under one of those names. 2. The operator launches `fastloop_trader.py`. 3. Python resolves the attacker-controlled module before the intended implementation. 4. The module's top-level code executes with the same operating-system per ...[truncated 1295 chars]
Remediation
## Remediation Suggestions - Remove the implicit ambient import if trade-journal integration is not essential to the declared trading functionality. - Require an explicit command-line or configuration opt-in before loading the integration. - Declare the dependency in a locked dependency manifest with an exact version and verified hashes. - Import only from a project-controlled, fully qualified package namespace rather than trying generic top-level names. - Package the trusted journal adapter with the Skill if its source can be reviewed and maintained securely. - Validate the resolved module origin using `importlib.util.find_spec()` and reject modules outside an approved installation directory. - Run the trader in an isolated virtual environment with a controlled `sys.path`; do not include attacker-writable directories or untrusted `PYTHONPATH` entries. - Avoid passing sensitive trade metadata to optional extensions unless the operator explicitly authorizes it.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises executable behavior that uses environment secrets, file/config writes, and network access, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates a least-privilege gap: an agent may invoke the skill with broader capabilities than intended, increasing the chance of unintended secret exposure, unauthorized external requests, or persistent config changes.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The description says to use the skill whenever a user wants to automate short-term crypto trading or use CEX momentum as a signal, which is broad enough to encourage opportunistic invocation without strong user confirmation or suitability checks. In a live-trading skill that can place real-money trades, ambiguous activation criteria materially increase the risk of accidental or overly eager execution.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The 'When to Use This Skill' section lists broad situations like automating short-term crypto prediction trading and monitoring sprint positions, but it does not define exclusions or safeguards. Given the skill's context—real USDC trading on Polymarket and support for looping/cron execution—this ambiguity makes unintended activation more dangerous than in a read-only or educational skill.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The `_update_config` function writes directly to `config.json`, modifying local files, but the function itself has no inline warning, confirmation, or explanatory comment about persisting changes. Although the CLI exposes `--set`, the actual file-write path is a safety-relevant operation that lacks explicit user disclosure in the code at the write site.

External Transmission

Medium
Category
Data Exfiltration
Content
Returns: {momentum_pct, direction, price_now, price_then, avg_volume, candles}
    """
    url = (
        f"https://api.binance.com/api/v3/klines"
        f"?symbol={symbol}&interval=1m&limit={lookback_minutes}"
    )
    result = _api_request(url)
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_coingecko_momentum(asset="bitcoin", lookback_minutes=5):
    """Fallback: get price from CoinGecko (less accurate, ~1-2 min lag)."""
    url = f"https://api.coingecko.com/api/v3/simple/price?ids={asset}&vs_currencies=usd"
    result = _api_request(url)
    if not result or isinstance(result, dict) and result.get("error"):
        return None
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Low
Confidence
83% confidence
Finding
The manifest frames the skill as a fast-market trading agent using Simmer API and CEX momentum signals. The code additionally imports and uses a tradejournal integration to record executed trades, which is a separate persistence/integration behavior not disclosed in the stated description.

Description-Behavior Mismatch

Low
Confidence
87% confidence
Finding
The manifest describes a trading skill driven by CEX momentum signals, but does not mention local state/config file modification. While configuration support is useful operationally, writing config.json is a behavior beyond the narrowly described trade-execution role.

Static analysis

No suspicious patterns detected.