Back to skill

Security audit

Kalshi Crypto Cycle Model Trader

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed live trading skill, but its safeguards and position-selection logic can affect real funds in ways users may not expect.

Install only if you are comfortable giving this skill live trading authority and a Solana private key. Keep it in dry-run unless you have reviewed the SDK, use limited and revocable credentials, set small trade limits, and avoid running live while other BTC/Kalshi positions are in the same account unless the exit logic is fixed.

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:310
Finding

Live-Trading Safeguards Fail Open When Market Context Is Unavailable

Content
View full analysis

Vulnerability Details

File Location: trader.py, lines 310-336
Vulnerability Type: Fail-open safety validation
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

Exceptions raised while retrieving market context are silently converted into None. The safeguard function then interprets missing context as approval and returns (True, []).

Consequently, failure to retrieve required safety information bypasses checks for:

  • Resolved markets
  • Severe strategy flip-flopping
  • Insufficient time before resolution
  • Minimum liquidity
  • Excessive slippage

This is a fail-open design. For financial operations, an inability to validate safety conditions must prevent execution rather than authorize it.

Attack Path

  1. The Skill identifies a market whose modeled edge exceeds the entry threshold.
  2. An API outage, malformed response, authentication failure, rate limit, or induced network disruption causes get_market_context() to raise an exception.
  3. The broad exception handler returns None without preserving or reporting the underlying failure.
  4. check_safeguards(None) returns True.
  5. When invoked with --live, the Skill proceeds to submit a real-money order without validated resolution, liquidity, or slippage da ...[truncated 382 chars]
Remediation
View remediation

Remediation Suggestions

  • Fail closed whenever market context cannot be retrieved:
    python
    if not context:
        return False, ["Market context unavailable"]
    
  • Catch expected SDK or network exceptions explicitly instead of using an unrestricted except Exception.
  • Log sanitized error details so operators can distinguish network failures, rate limits, and invalid API responses.
  • Validate the context response schema before approving a trade.
  • Require fresh, successfully validated context immediately before every live buy or sell operation.
  • Consider bounded retries with exponential backoff, but reject the trade if context remains unavailable.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
trader.py:416
Finding

Exit Logic Can Sell BTC Positions Not Created by This Skill

Content
View full analysis

Vulnerability Details

File Location: trader.py, lines 416-418
Vulnerability Type: Position ownership boundary violation
Risk Level: High

Vulnerable Code

python
btc_pos = [p for p in positions
           if TRADE_SOURCE in p.get("sources", [])
           or any(kw in (p.get("question") or "").lower() for kw in ["bitcoin", "btc"])]

Technical Analysis

The position filter uses a logical or. A position is therefore considered eligible for automated exit if either:

  • It carries this Skill's TRADE_SOURCE; or
  • Its question contains the text bitcoin or btc.

The second condition includes BTC positions opened manually or by unrelated strategies. Later, check_exits() submits a sell order when such a position reaches EXIT_THRESHOLD. This exceeds the minimum authority necessary for the declared strategy, which should manage only positions it created or was explicitly authorized to manage.

Text matching against a market question is not a reliable ownership or authorization control.

Attack Path

  1. A user or another strategy opens a BTC-related position.
  2. The position appears in the account-wide response from /api/sdk/positions.
  3. The position lacks this Skill's source tag, but its question contains bitcoin or btc.
  4. The or condition incorrectly includes it in btc_pos.
  5. Its current price reaches or exceeds the configured exit threshold.
  6. When running in live mode, the Skill submits a sell order for the unrelated position's shares.

Impact Assessment

The Skill can exercise account-level trading authority against positions outside its strategy ownership boundary. It may prematurely liquidate manually managed or third-party-strategy BTC holdings, interfere with other trading systems, realize unintended gains or losses, and alter the user's portfolio without explicit authorization.

Remediation
View remediation

Remediation Suggestions

  • Restrict exit management to positions carrying the exact Skill source:
    python
    btc_pos = [
        p for p in positions
        if TRADE_SOURCE in p.get("sources", [])
    ]
    
  • Prefer a securely persisted allowlist of market IDs or trade IDs created by this Skill.
  • Require both an ownership identifier and the expected strategy slug before selling.
  • Do not use market-question keywords as an authorization mechanism.
  • Add tests proving that unrelated BTC positions are never selected for exit.
  • If account-wide position management is desired, expose it as a separate, explicit opt-in setting with prominent warnings.

T08 · Insecure Dependencies

Warning
Location
clawhub.json:4
Finding

Unpinned Third-Party SDK Runs With Access to High-Value Trading Credentials

Content
View full analysis

Vulnerability Details

File Location: clawhub.json, lines 4-10; trader.py, lines 230-242
Vulnerability Type: Unpinned security-sensitive dependency
Risk Level: Medium

Vulnerable Code

json
"requires": {
  "env": [
    "SIMMER_API_KEY",
    "SOLANA_PRIVATE_KEY"
  ],
  "pip": [
    "simmer-sdk"
  ]
}

The dependency is imported and receives the API key:

python
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)

Technical Analysis

The manifest specifies simmer-sdk without an exact version or integrity hash. Package resolution can therefore install a later release whose implementation differs from the version originally reviewed.

The imported package executes within the same Python process and receives SIMMER_API_KEY, described by the Skill documentation as a high-value credential with trading authority. It also executes in a process whose environment is configured to include SOLANA_PRIVATE_KEY, although the local trader.py code does not directly read or transmit that private key.

No evidence shows that the currently intended SDK is malicious or that the local code directly exfiltrates the Solana key. The risk arises from granting a mutable third-party dependency access to credential-bearing process state.

Attack Path

  1. The Skill is installed at a later time with the unversioned simmer-sdk requirement.
  2. Package resolution selects a newly compromised, malicious, or unexpectedly changed release.
  3. Python impo ...[truncated 740 chars]
Remediation
View remediation

Remediation Suggestions

  • Pin simmer-sdk to an exact version that has been reviewed.
  • Use a lockfile and verified package hashes, such as pip's --require-hashes.
  • Monitor the pinned dependency and its transitive dependencies for advisories and ownership changes.
  • Remove SOLANA_PRIVATE_KEY from the manifest and runtime environment unless the local implementation demonstrably requires it.
  • Supply credentials only to the component that needs them, preferably through a constrained secret broker rather than the general process environment.
  • Use a trading API key with minimum permissions, strict spending limits, venue restrictions, and revocation support.
  • Review the SDK's source and network destinations before enabling live mode.
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 (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented purpose materially understates operational capabilities: the skill can use an additional private key, discover/import markets, manage existing positions, and mutate persistent config. This mismatch is dangerous because users may grant trust or credentials based on an incomplete description, leading to unexpected live trading behavior or broader-than-expected access to accounts and state.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Declaring access to a private key without a justified relationship to the skill's stated purpose is a strong overprivilege signal. In this context, the mismatch makes the skill more dangerous because users would reasonably expect only Kalshi/API credentials, not a wallet secret that could enable theft of on-chain assets if mishandled or abused.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares access to sensitive environment variables but does not define an explicit tool or permission scope. In an agent ecosystem, that omission weakens least-privilege boundaries and makes it harder for operators to understand or constrain what secrets the skill may access, especially since the skill is documented to use high-value credentials for trading.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The credential documentation is internally inconsistent: metadata says only SIMMER_API_KEY is required, while the body also requires SOLANA_PRIVATE_KEY for live trading. Inconsistent secret requirements can cause unsafe deployment decisions, such as supplying unnecessary high-value credentials or enabling live trading without operators realizing the full trust implications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest requires a highly sensitive credential but provides no user-facing warning or explanation about private-key handling. This increases the chance that users will supply a wallet secret without understanding the risk, creating avoidable exposure to credential theft, unauthorized signing, or misuse by the skill or its dependencies.

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 a SOLANA_PRIVATE_KEY even though the skill is described as a Kalshi Bitcoin cycle trader and only lists simmer-sdk as a dependency. Unnecessary access to a blockchain private key materially expands the blast radius: if the skill code, dependencies, or runtime are compromised, the key could be exfiltrated or used to sign unauthorized transactions unrelated to the stated trading function.

Content

No source excerpt is available for this finding.