Back to skill

Security audit

Kalshi F1 Constructor Trader

Security checks for vulnerabilities and agentic risk

Overview

This trading skill is mostly coherent and disclosed, but it needs review because live financial orders can proceed when safety context checks fail and it exposes a wallet private key broadly.

Install only after reviewing the live-trading risk. Use paper mode first, avoid providing SOLANA_PRIVATE_KEY unless you intend live trading, use a dedicated low-balance wallet and limited API key, and pin or isolate simmer-sdk before running with --live.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:297
Finding

Market Safety Checks Fail Open When Context Retrieval Fails

Content
View full analysis

Vulnerability Details

File Location: trader.py:297-313
Vulnerability Type: Fail-open validation of live trading safeguards
Risk Level: High

Vulnerable code:

python
def get_market_context(market_id: str, my_probability: float = None) -> 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, []

Technical Analysis

get_market_context() suppresses every exception and returns None. The downstream check_safeguards() function interprets a missing or empty context as authorization to proceed.

This is a fail-open security design. The unavailable context can contain the information needed to enforce resolution status, flip-flop warnings, time-to-resolution limits, liquidity requirements, and slippage limits. A network failure, authentication error, malformed SDK response, rate limit, or service disruption therefore disables all of these controls rather than stopping the transaction.

Because the same path is used before entry and exit orders, the issue can affect both purchases and sales in live mode.

Attack Path

  1. The Skill is started with --live.
  2. An F1 market meets the static model's entry or exit threshold.
  3. Context retrieval fails because of a service outage, rate limit, malformed response, network interference, or other SDK exception.
  4. get_market_context() catches the exception and returns None.
  5. check_safeguards(None) returns (True, []). ...[truncated 901 chars]
Remediation
View remediation

Remediation Suggestions

  • Fail closed whenever market context cannot be retrieved:
    python
    def check_safeguards(context: dict) -> tuple[bool, list[str]]:
        if not context:
            return False, ["Market context unavailable"]
    
  • Preserve and log a sanitized error reason rather than silently swallowing every exception.
  • Validate the context response schema and reject responses missing required market, warnings, discipline, or slippage information.
  • Use narrowly scoped exception handling for expected network and SDK errors.
  • Permit an explicit fail-open mode only for dry-run analysis, never for live execution.
  • Add tests proving that timeouts, HTTP errors, malformed responses, and empty contexts prevent live orders.

T08 · Insecure Dependencies

Warning
Location
clawhub.json:8
Finding

Unpinned Trading SDK Executes with Credential and Transaction Access

Content
View full analysis

Vulnerability Details

File Location: clawhub.json:8-10, SKILL.md:13, trader.py:205-218
Vulnerability Type: Unpinned privileged third-party dependency
Risk Level: Medium

Dependency declaration:

json
"pip": [
  "simmer-sdk"
]

Privileged use of the dependency:

python
def get_client(live=True):
    """Lazy-init SimmerClient singleton."""
    global _client
    if _client is None:
        try:
            from simmer_sdk import SimmerClient
        except ImportError:
            print("Error: simmer-sdk not installed. Run: pip install simmer-sdk")
            sys.exit(1)
        api_key = os.environ.get("SIMMER_API_KEY")
        if not api_key:
            print("Error: SIMMER_API_KEY environment variable not set")
            print("Get your API key from: simmer.markets/dashboard -> 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 specifies simmer-sdk without an exact version or artifact hash. Package resolution can therefore install a future release that was not reviewed with this Skill.

The dependency is security-sensitive: its code is imported into the main process, receives SIMMER_API_KEY, performs authenticated network requests, and submits live financial transactions. Python modules also execute top-level initialization code at import time, so a compromised package release would not need to wait for a client method call before accessing process resources.

The audit did not find evidence that the currently intended SDK is malicious. The vulnerability is the lack of reproducible, integrity-verified dependency resolution for a package operating with high-value credentials.

Attack Path

  1. An attacker compromises the package publisher, release pipeline, package registry a ...[truncated 1025 chars]
Remediation
View remediation

Remediation Suggestions

  • Pin simmer-sdk to a specific audited version in both metadata and installation documentation.
  • Require a hash-verified installation through a locked requirements file, for example with --require-hashes.
  • Record and verify hashes for all transitive dependencies.
  • Use an isolated virtual environment with only the minimum required packages.
  • Monitor the pinned version for security advisories and update it through a documented review process.
  • Prefer a transaction architecture in which dependency code cannot directly access exportable wallet secrets.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
clawhub.json:3
Finding

Wallet Private Key Is Declared as a Global Requirement Despite No Direct Use

Content
View full analysis

Vulnerability Details

File Location: clawhub.json:3-7, SKILL.md:78-99, trader.py:205-218
Vulnerability Type: Excessive credential exposure and violation of least privilege
Risk Level: Medium

Credential declaration:

json
"requires": {
  "env": [
    "SIMMER_API_KEY",
    "SOLANA_PRIVATE_KEY"
  ],

Actual credential access in the client initialization code:

python
def get_client(live=True):
    """Lazy-init SimmerClient singleton."""
    global _client
    if _client is None:
        try:
            from simmer_sdk import SimmerClient
        except ImportError:
            print("Error: simmer-sdk not installed. Run: pip install simmer-sdk")
            sys.exit(1)
        api_key = os.environ.get("SIMMER_API_KEY")
        if not api_key:
            print("Error: SIMMER_API_KEY environment variable not set")
            print("Get your API key from: simmer.markets/dashboard -> 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 Skill metadata requires SOLANA_PRIVATE_KEY for the package as a whole, including default dry-run and position-inspection use. However, trader.py never reads that variable directly. The only credential explicitly retrieved by the implementation is SIMMER_API_KEY.

Environment variables are process-wide rather than capability-scoped. If the platform injects every declared requirement when launching the Skill, all imported Python modules and optional integrations can access the wallet private key, even in modes that do not need signing authority.

No direct private-key transmission, SSH-key operation, or explicit exfiltration was found in the reviewed source. The risk arises from unnecessarily making an exportable wallet secret available to the entire process and it ...[truncated 1224 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove SOLANA_PRIVATE_KEY from unconditional package-level requirements.
  • Request signing authority only after an explicit live-mode decision and only for the shortest possible duration.
  • Use a separate launcher or isolated signing service for live execution so dry-run and read-only modes never receive the key.
  • Prefer a non-exportable signer, hardware wallet, delegated session key, or narrowly scoped transaction-signing API.
  • Ensure read-only operations use credentials without transaction authority.
  • Document which component consumes the key and why it is required.
  • Scrub unnecessary secrets from the environment before importing optional or third-party modules.
  • Apply wallet-side spending and destination restrictions so compromise of the Skill process does not imply unrestricted wallet control.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill requests and documents access to sensitive environment variables used for trading, but it does not declare an explicit tool scope or permissions boundary. In an agent ecosystem, undeclared env access weakens reviewability and can expose high-value credentials such as SIMMER_API_KEY and SOLANA_PRIVATE_KEY to skill logic without clear least-privilege controls.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest declares only SIMMER_API_KEY as required, while the setup and credential sections also require SOLANA_PRIVATE_KEY for live trading. This inconsistency can cause operators or automated reviewers to underappreciate that the skill needs a private signing key, increasing the chance that a highly sensitive credential is handled, injected, or approved without proper scrutiny.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest requests a SOLANA_PRIVATE_KEY even though the skill is described as a Kalshi F1 constructor trader and only documents SIMMER_API_KEY and simmer-sdk as necessary. Requiring an unrelated blockchain private key expands the secret exposure surface and could enable unauthorized wallet access or signing if the runtime or downstream code ever reads or exfiltrates that key.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Declaring a sensitive private key requirement without explicit disclosure is dangerous because users may provide a high-value secret without understanding why it is needed or what transactions it could authorize. In this skill's context, the mismatch between an F1/Kalshi trading description and a Solana wallet secret makes the omission more suspicious and increases the risk of covert credential harvesting.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest frames this skill as trading Kalshi F1 Drivers Championship markets using a constructor-based model. However, the file explicitly advertises and requires live execution through DFlow/Solana, adding an execution pathway and wallet dependency beyond the manifest's stated scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

When run with --live, the skill places real buy orders immediately based solely on computed signals, with no interactive confirmation, approval gate, or secondary safety check at execution time. In a trading skill handling real funds, this materially increases the risk of accidental or unintended trades from operator error, misconfiguration, bad model assumptions, or unsafe automation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The manifest description presents a narrowly scoped strategy based on constructor car performance ratings for Drivers Championship markets. The body documentation broadens this into a reusable trading template with market discovery, execution, and support for live qualifying, practice, and development-trajectory data, which exceeds the narrow behavior implied by the manifest summary.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest describes a trading strategy skill, but the code also includes persistent configuration management capabilities via load_config/update_config/get_config_path and exposes them through CLI settings updates. This is additional behavior beyond the narrow description of trading based on constructor ratings.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

Accepting --set KEY=VALUE and calling update_config allows the skill to write persistent local configuration, changing future behavior. While useful operationally, this capability is separate from the core purpose of evaluating F1 markets and placing trades, and is not disclosed in the manifest.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.