Back to skill

Security audit

Kalshi Econ Bin Sum Trader

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed trading skill that defaults to dry-run, but live use gives it high-impact trading and wallet authority with several under-scoped financial safety risks.

Use this only in dry-run until the SDK version, credential handling, grouping logic, safeguard behavior, and exit ownership rules are reviewed. For live mode, use a dedicated low-balance account or wallet, tightly limited trading credentials, and avoid accounts containing unrelated CPI positions.

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

T08 · Insecure Dependencies

Error
Location
clawhub.json:3
Finding

Unpinned Trading SDK Has Access to High-Value Credentials

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 `simmer-sdk` dependency is specified without an exact version or package hash. Installation can consequently resolve to a future package release that was not covered by this audit. The dependency is imported into a process that contains `SIMMER_API_KEY` and is configured to contain `SOLANA_PRIVATE_KEY`. Python dependencies execute with the privileges and environment of the host process. A compromised SDK release could read all process environment variables, transmit credentials, alter market data returned to the strategy, or execute unauthorized trades. The project code passes `SIMMER_API_KEY` to the declared `SimmerClient`; no direct transmission of the credential to an unrelated endpoint was found in the audited project files. `SOLANA_PRIVATE_KEY` is declared as required but is not directly read by `trader.py`. Nevertheless, an imported depen ...[truncated 1103 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:365
Finding

Trading Safeguards Fail Open When Market Context Is Unavailable

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, [] reasons = [] market = context.get("market", {}) warnings = context.get("warnings", []) discipline = context.get("discipline", {}) slippage = context.get("slippage", {}) ``` The approval result is subsequently used before live order execution: ```python ctx = get_market_context(b["market_id"], my_probability=fair_p if side == "yes" else 1 - fair_p) ok, reasons = check_safeguards(ctx) if not ok: log(f" Skipped: {'; '.join(reasons)}") skip_reasons.extend(reasons) continue if not dry_run: result = execute_trade( b["market_id"], side, size, ``` ### Technical Analysis `get_market_context()` catches every exception and converts the failure into `None`. `check_safeguards()` then explicitly treats a missing or otherwise false context value as approval by returning `(True, [])`. This behavior bypasses all subsequent checks for resolved markets, flip-flop warnings, time to resolution, minimum liquidity, and excessive slippage. The safest behavior for a financial execution system is t ...[truncated 1352 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
trader.py:449
Finding

Exit Logic Can Sell CPI Positions Not Opened by This Skill

Content
View full analysis
tuple[int, int]: """Check open CPI bin-sum positions for exit opportunities.""" positions = get_positions() if not positions: return 0, 0 cpi_pos = [p for p in positions if TRADE_SOURCE in p.get("sources", []) or is_cpi_market(p.get("question") or "")] if not cpi_pos: return 0, 0 log(f"\n Checking {len(cpi_pos)} CPI bin-sum positions for exit...") found, executed = 0, 0 for pos in cpi_pos: market_id = pos.get("market_id") price = pos.get("current_price") or pos.get("price_yes") or 0 shares = pos.get("shares_yes") or pos.get("shares") or 0 question = pos.get("question", "")[:50] if shares < MIN_SHARES_PER_ORDER: continue if price >= EXIT_THRESHOLD: found += 1 log(f" EXIT: {question} price={price:.2f} >= {EXIT_THRESHOLD:.2f}") ctx = get_market_context(market_id) ok, reasons = check_safeguards(ctx) if not ok: log(f" Skipped: {'; '.join(reasons)}") continue if not dry_run: result = execute_trade( market_id, "sell", shares, reasoning=f"Exit: price {price:.2f} >= threshold {EXIT_THRESHOLD:.2f}", ) ``` ### Technical Analysis The position filter uses an `or` condition. A position qualifies either when it contains this Skill's source identifier or when its question merely includes a CPI-related keyword. Consequently, ownership is not required before the Skill exercises sell authority. Positions opened manually, by another Skill, or by another strategy can be selected and liquidated. Keyword matching is no ...[truncated 1136 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
trader.py:175
Finding

Heuristic Event Grouping Can Generate Trades from Non-Exclusive Markets

Content
View full analysis
str: """Extract the event group identifier from a CPI market question. Groups bins that belong to the same mutually exclusive set (e.g., "January 2026 CPI" bins should sum to 100%). """ q = question.lower() # Try to extract month + year months = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"] for month in months: if month in q: # Find year years = re.findall(r'20\d{2}', q) if years: return f"{month}_{years[0]}" return month # Try quarter quarters = re.findall(r'q[1-4]\s*20\d{2}', q) if quarters: return quarters[0].replace(" ", "_") # Fallback: use full question hash return "cpi_general" ``` The generated key is used to combine markets: ```python lo, hi = bin_range group_key = extract_event_group(question) groups[group_key].append({ "market_id": market_id, "question": question, "price": price, "lower": lo, "upper": hi, }) if not groups: log(" No parseable CPI bin groups found") return for group_key, bins in groups.items(): if len(bins) < 2: log(f"\n Group '{group_key}': only {len(bins)} bin(s) -- need >= 2, skipping") continue bins.sort(key=lambda b: b["lower"]) total_p = sum(b["price"] for b in bins) deviation = abs(total_p - 1.0) ``` ### Technical Analysis The strategy assumes every market placed in one group is part of a mutually exclusive and collectively exhaustive outcome set. However, the grouping key is inferred only from month and y ...[truncated 2173 chars]
Remediation
View remediation
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
96% confidence
Finding

The documentation understates the skill's capabilities by omitting an additional high-value credential and several operational behaviors, including position management, market import/discovery, persistent configuration updates, and reporting/logging. This mismatch can mislead users into granting sensitive credentials or deploying the skill with more authority and side effects than they intended.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

A Solana wallet credential is context-inappropriate for a Kalshi bin-sum trading skill, making the requirement suspicious and dangerous. In this context, an unnecessary private key could be harvested, misused for unrelated on-chain transactions, or retained by code paths the user would not reasonably expect from the stated strategy.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest enables automated trading while requiring a private key, but provides no user-facing warning about sensitive credential handling, signing authority, or transaction risk. That combination is especially dangerous because users may supply a high-value secret without understanding that the agent could initiate irreversible financial actions or expose wallet access beyond the advertised Kalshi strategy.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill declares environment-variable requirements but does not declare an explicit tool/permission scope. In an agent ecosystem, missing scope declarations weaken least-privilege controls and can cause operators or orchestrators to underestimate what sensitive resources the skill may access.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Claiming 'mathematical certainty' and 'guaranteed mispricing' overstates the strategy and can induce unsafe operator behavior, such as trusting losses are impossible or relaxing oversight on live trading. In a trading skill handling real funds, misleading safety or profitability claims are dangerous because they distort risk assessment and deployment decisions.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest requests a SOLANA_PRIVATE_KEY even though the skill description only mentions Kalshi CPI bin trading and SIMMER_API_KEY. Requiring an unrelated blockchain private key materially expands the credential exposure surface and could enable unauthorized wallet access or signing if the runtime or downstream code uses that secret.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The CLI supports persistent configuration changes via --set, which writes updated values using update_config(...). In a trading skill, allowing local persistent mutation of execution parameters such as slippage, max position size, and trade count can materially change future behavior, and this state-changing capability is not reflected in the stated manifest behavior. While not overtly malicious, undocumented persistent state changes increase auditability and supply-chain risk because a caller or wrapper can silently weaken safeguards for later runs.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The template text says the skill 'handles all the plumbing (market discovery, trade execution, safeguards),' which implies actionable execution capability, while later sections emphasize default dry-run mode and live trading only with an explicit flag. This is not a direct code contradiction, but it creates intent ambiguity about whether execution is automatic or gated.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill optionally imports and uses a tradejournal integration to send trade metadata outside the core trading path, but this external logging behavior is not disclosed in the manifest. Even if the payload appears limited to trade IDs and thesis strings, undeclared outbound integrations can leak sensitive strategy or account activity data and expand the attack surface through an unreviewed dependency.

Content

No source excerpt is available for this finding.