Back to skill

Security audit

Kalshi F1 Points Model Trader

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent as a trading tool, but it should be reviewed carefully because it can place live trades and exposes high-value credentials to an unpinned trading SDK with weak fail-closed safeguards.

Install only if you understand that --live can place and close real Kalshi trades using high-value credentials. Use a low-balance, dedicated wallet/API key, review or pin simmer-sdk before providing SOLANA_PRIVATE_KEY, keep dry-run mode until safeguards fail closed, and verify trade-size limits match your risk tolerance.

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

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding

Unpinned Third-Party Dependency Receives Unnecessary Access to a Wallet Private Key

Content
View full analysis
SDK tab") sys.exit(1) venue = os.environ.get("TRADING_VENUE", "kalshi") _client = SimmerClient(api_key=api_key, venue=venue, live=live) return _client ``` ### Technical Analysis The project declares `simmer-sdk` without an exact version or integrity hash. Consequently, installation can resolve to a package release that differs from the version reviewed by an operator. The Skill also declares `SOLANA_PRIVATE_KEY` as a process-wide required environment variable, although `trader.py` never reads that variable directly. Any imported Python dependency executes in the same process and can access inherited environment variables through `os.environ`. Therefore, the unpinned SDK and its transitive dependencies receive ambient access to a high-value wallet credential beyond what the audited local implementation demonstrably requires. The direct transmission of `SIMMER_API_KEY` to `SimmerClient` is consistent with the declared authenticated trading function. No direct private-key collection or exfiltration was found in the three audited projec ...[truncated 1259 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:329
Finding

Market Trading Safeguards Fail Open When Context Retrieval Fails

Content
View full analysis
dict: """Get market context with safeguards and edge analysis.""" try: if my_probability is not None: return get_client()._request( "GET", f"/api/sdk/context/{market_id}", params={"my_probability": my_probability} ) return get_client().get_market_context(market_id) except Exception: return None def check_safeguards(context: dict) -> tuple[bool, list[str]]: """Check context for safeguards. Returns (should_trade, reasons).""" if not context: return True, [] ``` The result is used as follows: ```python ctx = get_market_context( market_id, my_probability=model_p if side == "yes" else 1 - model_p ) ok, reasons = check_safeguards(ctx) if not ok: log(f" Skipped: {'; '.join(reasons)}") skip_reasons.extend(reasons) continue ``` ### Technical Analysis `get_market_context()` catches every exception and converts it to `None`, discarding the cause. `check_safeguards()` then interprets any false-valued context as approval by returning `(True, [])`. This reverses the appropriate trust boundary for live financial operations. The context contains checks for resolved markets, discipline warnings, time to resolution, liquidity, and slippage. If the API is unavailable, returns malformed data, rejects authentication, or experiences a transient network failure, all these controls are silently bypassed. Because execution proceeds after `ok` is set to `True`, the absence of validated context is treated as equivalent to successful validation. ### Attack Path 1. The Skill identifies a model signal that meets its entry threshold. 2. An attacker disru ...[truncated 1071 chars]
Remediation
View remediation
tuple[bool, list[str]]: if not isinstance(context, dict) or not context: return False, ["Market context unavailable or invalid"] ``` 2. Preserve and log the underlying exception without including credentials or sensitive request headers. 3. Validate the expected context schema before approving a trade. 4. Distinguish transient failures from permanent failures and implement bounded retries with backoff. 5. Do not place a live order if required slippage, liquidity, market-state, or resolution data is absent. 6. If context-free execution is operationally required, place it behind an explicit command-line override that is disabled by default and clearly warns about financial risk. 7. Add tests confirming that network exceptions, malformed JSON, empty responses, authentication failures, and missing safeguard fields all block live execution. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
trader.py:75
Finding

Minimum Order Floor Can Override the External Maximum-Bet Limit

Content
View full analysis
BUY {side.upper()}: |edge|={abs(edge):.1%} size=${size:.2f}") ``` ### Technical Analysis `AUTOMATON_MAX_BET` is applied as an upper bound to `MAX_POSITION_USD`. The subsequent sizing calculation independently imposes a minimum order amount of `$1.00` using `max(1.0, ...)`. If the effective external cap is below `$1.00`, the minimum-order expression raises the order size above the cap. No final validation ensures that `size <= MAX_POSITION_USD` immediately before order execution. A hard financial policy limit should take precedence over strategy sizing and minimum-order preferences. If the cap cannot satisfy the venue minimum, the trade should be rejected rather than enlarged. ### Attack Path 1. An operator or automation controller sets `AUTOMATON_MAX_BET` to a value below `$1.00`, such as `$0.50`. 2. Initialization sets `MAX_POSITION_USD` to `$0.50`. 3. A qualifying market signal reaches the sizing logic. 4. `max(1.0, calculated_size)` raises the order amount to at least `$1.00`. 5. In live mode, the Skill submits an order exceeding the configured external cap. This path does not require a remote attacker; it is triggered by a valid policy configuration that the code handles incorrectly. ### Impact Assessment The Skill can violate an operator-defined maximum-bet policy and create greater financial exposure than authorized. The overage is most di ...[truncated 302 chars]
Remediation
View remediation
MAX_POSITION_USD: log("Skipped: calculated order exceeds maximum position limit") continue ``` 4. Validate `AUTOMATON_MAX_BET` as a finite, non-negative numeric value and handle invalid values without crashing. 5. Clarify whether the limit is per order, per market, or per execution cycle, and enforce the intended semantics consistently. 6. Add unit tests for caps below, equal to, and above the minimum order size. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The public description frames the skill as a modeling/trading utility requiring only SIMMER_API_KEY, but the documentation also reveals live trade execution, position management, market discovery, and use of SOLANA_PRIVATE_KEY. This mismatch can cause operators to grant more trust and more powerful credentials than intended, increasing the risk of unauthorized real-money trades or secret exposure in a high-impact financial context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Access to a Solana private key is unjustified by the stated purpose of computing F1 points-model probabilities and trading Kalshi markets, making the secret request a strong indicator of credential overreach. In agent environments, exposing a private key to an unnecessary skill can lead directly to wallet compromise, asset theft, or malicious on-chain transactions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill requests access to sensitive environment variables but does not declare an explicit tool scope or permissions boundary in the manifest. In a trading skill that handles API keys and a private key, this increases the chance of overbroad secret exposure and makes it harder for a platform or reviewer to enforce least privilege.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The template text states that the default signal already uses static points standings and driver ratings to simulate the remaining season, implying implemented strategy logic. However, this file contains only descriptive documentation and setup notes, with no actual model inputs, simulation code, or static standings data shown. That is an active mismatch between the documentation's representation of current behavior and what this artifact actually contains.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest requests SOLANA_PRIVATE_KEY despite the skill being described solely as a Kalshi F1 championship trader that needs only market/data access. Requesting an unrelated blockchain private key creates unnecessary exposure of highly sensitive credentials and could enable theft or unauthorized signing if the skill or its dependencies access the key.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest describes a skill for trading F1 championship winner markets on Kalshi using a points model, but the file-level documentation and code also require a SOLANA_PRIVATE_KEY for live trading and route execution through the Simmer SDK with DFlow/Solana-backed live execution. That expands the described behavior from market analysis and Kalshi trading logic into wallet-backed execution infrastructure not mentioned in the manifest.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill metadata says it requires SIMMER_API_KEY, while later setup instructions also require SOLANA_PRIVATE_KEY for live trading. Contradictory secret requirements can cause unsafe deployment decisions, such as supplying unnecessary high-value credentials or misunderstanding when live trading authority is available.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The stated purpose is to trade Kalshi F1 championship markets using a Monte Carlo points model, but the CLI also allows persistent configuration changes via --set and update_config. Modifying local skill configuration is not a direct, obvious requirement of the trading strategy itself and represents an extra management capability.

Content

No source excerpt is available for this finding.