Back to skill

Security audit

Kalshi Eth Btc Beta Trader

Security checks for vulnerabilities and agentic risk

Overview

This trading skill is mostly coherent, but it asks for high-value financial credentials and performs some authenticated account changes under a dry-run workflow, so it should receive manual review before installation.

Install only if you are comfortable giving the skill and its Python dependencies access to Simmer trading credentials and a Solana private key. Prefer a dedicated low-balance trading wallet, avoid providing SOLANA_PRIVATE_KEY for dry-run or read-only use, review/pin simmer-sdk before live use, and expect default runs to potentially import markets into your Simmer account even when no trades are placed.

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)

T08 · Insecure Dependencies

Warning
Location
clawhub.json:7
Finding
Unpinned Privileged Trading Dependency Creates a Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `clawhub.json:7-9` **Vulnerability Type**: Unpinned third-party dependency with access to financial credentials and trading operations **Risk Level**: Medium ### Vulnerable Code Snippet ```json "pip": [ "simmer-sdk" ] ``` The dependency is imported and given the trading API key in `trader.py:48` and `trader.py:186-194`: ```python from simmer_sdk.skill import load_config, update_config, get_config_path ``` ```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) ``` ### Technical Analysis The project requests `simmer-sdk` without an exact version, artifact hash, or lock-file constraint. Package resolution can therefore select a newer release than the one reviewed when this Skill was published. The package executes in the same Python process as the Skill and is explicitly given `SIMMER_API_KEY`. Like any imported Python module, it can also inspect all environment variables available to the process, including `SOLANA_PRIVATE_KEY` when users follow the manifest requirements. The SDK controls authenticated network requests and trade execution, making it part of the trusted financial execution boundary. The project documentation identifies a package publisher and source repository, but this does not cryptographically bind the package installed from PyPI to a reviewed source ...[truncated 1584 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `simmer-sdk` to an exact, audited version rather than accepting any available version. 2. Use a lock file and verify package artifacts with cryptographic hashes, such as pip's `--require-hashes`. 3. Re-audit the SDK before upgrading the pinned version. 4. Generate a software bill of materials and continuously monitor the dependency and its transitive dependencies for compromise or known vulnerabilities. 5. Run the trading process in a restricted environment with access only to credentials required for the selected execution mode. 6. Keep wallet signing outside the general Python process where possible, using a narrowly scoped signer or wallet service. 7. Apply API-side transaction, venue, and spending limits so a compromised client cannot exercise unrestricted financial authority. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
clawhub.json:3
Finding
Wallet Private Key Is Required Beyond the Skill's Demonstrated Needs<![CDATA[ ## Vulnerability Details **File Location**: `clawhub.json:3-6` **Vulnerability Type**: Excessive credential requirement and violation of least privilege **Risk Level**: Medium ### Vulnerable Code Snippet ```json "requires": { "env": [ "SIMMER_API_KEY", "SOLANA_PRIVATE_KEY" ], ``` The same requirement is communicated in `SKILL.md:68-70`: ```markdown ## Installation & Setup ```bash clawhub install kalshi-eth-btc-beta-trader ``` Requires: `SIMMER_API_KEY` and `SOLANA_PRIVATE_KEY` environment variables. ``` The implementation only explicitly retrieves the Simmer credential at `trader.py:189`: ```python api_key = os.environ.get("SIMMER_API_KEY") ``` No code in `trader.py` explicitly reads `SOLANA_PRIVATE_KEY`. ### Technical Analysis The manifest requires users to expose a base58-encoded Solana private key to the entire Skill process even though the audited implementation never directly retrieves that variable. The requirement also applies at installation/configuration level rather than being conditioned on explicit live execution. This exceeds the minimum privilege visibly necessary for dry-run analysis, configuration display, position viewing, market discovery, and other read-oriented operations. Every in-process Python dependency can inspect the process environment, so unnecessarily provisioning the key expands the number of components and execution paths that can access a high-value credential. The documentation states that the key is intended for live trading via DFlow/Solana. If the SDK implicitly consumes it, that behavior is outside the project code available for this audit and should still be restricted to live mode rather than imposed on all operation modes. ### Attack Path 1. A user follows `clawhub.json` and `SKILL.md` and exports `SOLANA_PRIVATE_KEY` before running the Skill. 2. The user invokes dry-run, configuration, position-viewing, or another operation that does not visibly require wallet signing. 3. Python loads ...[truncated 1116 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `SOLANA_PRIVATE_KEY` from the unconditional manifest requirements unless it is demonstrably required by audited code. 2. Do not request or provision the wallet key for dry-run, configuration, discovery, or read-only position operations. 3. If live settlement requires signing, request signing capability only after the user explicitly selects `--live`. 4. Prefer a dedicated low-balance trading wallet rather than a general-purpose wallet. 5. Replace raw private-key exposure with a narrowly scoped external signer, hardware wallet, or wallet service that enforces transaction policy. 6. Apply destination, program, asset, transaction-size, and cumulative-spending restrictions where the signing architecture supports them. 7. Document exactly which component consumes the key, which endpoint or chain operation requires it, and the authority that possession of the key grants. 8. Ensure logs, crash reports, configuration output, and diagnostics never serialize the key. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
trader.py:524
Finding
Dry-Run Mode Performs Authenticated Remote State Changes<![CDATA[ ## Vulnerability Details **File Location**: `trader.py:524-538` **Vulnerability Type**: Misleading dry-run semantics and remote side effects **Risk Level**: Low ### Vulnerable Code Snippet ```python # Init client get_client(live=not dry_run) # Positions only if positions_only: positions = get_positions() eth_pos = [p for p in positions if "eth" in (p.get("question") or "").lower() or "ethereum" in (p.get("question") or "").lower()] if not eth_pos: log(" No ETH positions") for p in eth_pos: log(f" {p.get('question', '')[:60]} price={p.get('current_price', 0):.2f}") return # --- Discovery --- log("Discovering ETH price markets on Kalshi...") newly = discover_and_import(log=log) if newly: log(f" Imported {newly} new ETH markets") log("Discovering BTC markets for beta reference...") btc_newly = discover_btc_markets(log=log) ``` The called functions perform remote imports at `trader.py:268-269` and `trader.py:300-301`: ```python try: result = client.import_kalshi_market(url) status = result.get("status", "") if result else "" ``` ```python try: result = client.import_kalshi_market(url) status = result.get("status", "") if result else "" ``` ### Technical Analysis The command-line interface defines dry-run as the default by setting `dry_run = not args.live`. Trade submission is correctly skipped in dry-run mode, but market discovery and `import_kalshi_market` calls are performed regardless of `dry_run`. Importing a market is an authenticated remote operation capable of modifying state associated with the Simmer account. Consequently, the default mode is not side-effect-free: it prevents trade execution but can still create or register imported markets and consume API quota. The documentation says dry-run has no financial risk and specifically promises that no trades execute. It does not explicitly promise that no remote account state changes occur, so this i ...[truncated 1313 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Skip `import_kalshi_market` calls whenever `dry_run` is true. 2. Add an explicit option such as `--import-markets` for remote market registration. 3. Require clear confirmation before authenticated state-changing discovery operations. 4. Separate read-only market search from market import so opportunity analysis does not require mutation. 5. Update documentation to distinguish among: - fully read-only preview, - paper trading, - market import, - live financial execution. 6. Add tests asserting that default dry-run mode never invokes trade or import methods. 7. If imports are indispensable for analysis, provide a temporary preview endpoint or document and display the exact side effects before execution. ]]>
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)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose understates the skill's actual capabilities, including use of an additional private key, position management, market discovery, persistent configuration changes, and optional external logging. This mismatch can cause users or automated policy systems to approve a skill under false assumptions, exposing trading funds, credentials, or data to broader operations than intended.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
Requesting `SOLANA_PRIVATE_KEY` is unjustified by the stated purpose of Kalshi ETH/BTC beta trading, making the secret request suspicious and materially increasing attack surface. In a skill that trades on Kalshi, an unrelated wallet private key could be exfiltrated or misused without user expectation, causing direct loss of on-chain funds.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill requests and uses sensitive environment-backed credentials but does not declare an explicit tool scope or permissions boundary in the manifest. In an agent ecosystem, this weakens operator visibility and policy enforcement, making it easier for the skill to access secrets or capabilities beyond what a reviewer expects.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The manifest requests `SOLANA_PRIVATE_KEY` even though the skill is described as a Kalshi ETH/BTC trading strategy that only claims to need `SIMMER_API_KEY` and `simmer-sdk`. Requesting an unrelated blockchain private key creates unnecessary secret exposure and could enable theft or unauthorized signing if later code accesses that variable.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The manifest asks for a private key environment variable with no warning, consent language, or explanation to the user. Even if not actively malicious, collecting a raw private key without prominent disclosure is unsafe because users may provide highly privileged credentials they do not realize are unrelated to the advertised strategy.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill advertises a simpler requirement set while also supporting real-money live trading that depends on additional sensitive credentials and operational risk. This can mislead an operator into enabling `--live` without fully understanding that the skill can place real trades and may require wallet key material, increasing the chance of accidental fund exposure or unintended execution.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The manifest says only SIMMER_API_KEY is required, while setup instructions and later sections additionally require SOLANA_PRIVATE_KEY. Credential inconsistencies create a review and deployment hazard: operators may provide a sensitive private key without having seen it declared up front, or security controls may fail to classify the skill as wallet-accessing.

Description-Behavior Mismatch

Low
Confidence
88% confidence
Finding
The stated purpose is to trade ETH price markets using BTC as a signal source. While reading BTC market data is expected, this implementation goes further by actively importing BTC markets with `import_kalshi_market`, which is an additional side effect not conveyed by the manifest description.

Context-Inappropriate Capability

Low
Confidence
86% confidence
Finding
The skill's purpose is market analysis and trading based on ETH/BTC beta lag. Adding a CLI path that writes updated configuration via `update_config` introduces local state mutation unrelated to the core trading capability and not mentioned in the manifest.

Static analysis

No suspicious patterns detected.