Back to skill

Security audit

Kalshi

Security checks for vulnerabilities and agentic risk

Overview

This Kalshi skill is a disclosed read-only market and portfolio viewer, but users should handle the local Kalshi API credentials carefully.

Install in an isolated Python environment, pin or review dependencies where possible, and only configure Kalshi API credentials if you need portfolio features. Treat the private key and ~/.kalshi/credentials.json as sensitive secrets, and do not rely on the opportunity output as financial advice.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding

Unpinned Third-Party Dependencies Create a Supply-Chain Execution Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:18-21; scripts/kalshi_portfolio.py:23-26
Vulnerability Type: Unpinned and unverifiable third-party dependencies
Risk Level: Medium

Affected code in SKILL.md:18-21:

bash
Install dependencies:
```bash
pip install requests cryptography
text

**Affected code in `scripts/kalshi_portfolio.py:23-26`:**
```python
if not HAS_SDK:
    print("Error: kalshi-python not installed. Run: pip install kalshi-python")
    sys.exit(1)

Technical Analysis

The project directs users to install requests, cryptography, and kalshi-python from the default Python package index without pinning reviewed versions, verifying cryptographic hashes, or supplying a lockfile. The documented setup also omits kalshi-python, while the portfolio script recommends installing it dynamically when an import fails.

Python package installation may execute package build hooks and installs code that will later run with the privileges of the invoking user. Because package names alone resolve to mutable versions and transitive dependency graphs, the reviewed project does not guarantee that users will install the same dependency code that was evaluated during this audit.

No evidence shows that the currently named packages are malicious. The vulnerability is the absence of dependency integrity and reproducibility controls, which exposes installation to a compromised package release, maintainer account, package index, or transitive dependency.

Attack Path

  1. An attacker compromises a named dependency, one of its transitive dependencies, its publisher account, or the package-index delivery path.
  2. The attacker publishes a malicious version under a package name recommended by the project.
  3. A user follows pip install requests cryptography or the runtime recommendation to execute pip install kalshi-python.
  4. Pip resolves the unpinned dependency to the attacker- ...[truncated 890 chars]
Remediation
View remediation

Remediation Suggestions

  1. Add all direct dependencies, including kalshi-python, to a version-controlled dependency manifest.
  2. Pin each dependency to an explicitly reviewed version rather than allowing installation of the latest available release.
  3. Generate and verify cryptographic hashes for direct and transitive packages, such as through a locked requirements file used with pip install --require-hashes.
  4. Regenerate the lockfile through a controlled review process and test dependency updates before release.
  5. Recommend installation inside a dedicated virtual environment with no elevated privileges.
  6. Replace the runtime message with installation instructions referencing the locked project dependency file, for example:
    python
    print("Error: dependencies are missing. Install the reviewed lockfile in an isolated virtual environment.")
    
  7. Use dependency scanning and provenance checks in CI to detect known vulnerabilities, unexpected ownership changes, and tampered release artifacts.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This finding combines multiple mismatches: the skill is labeled read-only yet instructs interactive credential collection and local secret storage, and it also overstates other features. In a security-sensitive agent context, misleading capability claims can cause unnecessary exposure of API keys and private keys while reducing operator awareness of what the skill really does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This finding combines multiple mismatches: the skill is labeled read-only yet instructs interactive credential collection and local secret storage, and it also overstates other features. In a security-sensitive agent context, misleading capability claims can cause unnecessary exposure of API keys and private keys while reducing operator awareness of what the skill really does.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

The skill instructs users to create and store persistent credentials locally, including an API key identifier and path to a private signing key. In an agent environment with shell/file capabilities and undeclared scope, this creates a meaningful secret-exposure risk through accidental reads, exfiltration, or misuse of account-linked authentication material.

Content

Scanner excerpt · SKILL.md (reported line 36)May include surrounding context.

chmod 600 ~/.kalshi/private_key.pem

text

4. Create `~/.kalshi/credentials.json`:
```json
{
  "api_key_id": "your-key-id-here",

Credential Access

High
Category
Privilege Escalation
Confidence
82% confidence
Finding

The script reads persistent API credentials from a predictable file in the user's home directory and later loads the private key into process memory for authenticated API use. This is sensitive credential access; if the file is exposed through weak permissions, backups, multi-user access, or other local compromise, an attacker could authenticate to the user's Kalshi account.

Content

Scanner excerpt · scripts/kalshi_portfolio.py (reported line 19)May include surrounding context.

python
except ImportError:
    HAS_SDK = False

CREDENTIALS_PATH = Path.home() / ".kalshi" / "credentials.json"


def load_credentials() -> dict:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill advertises shell, file-write, and network-capable behavior but does not declare explicit tool scope or permissions. In an agent environment, this weakens containment and can let a broadly triggered skill access local files, persist data, or make external requests beyond what users would reasonably expect from a read-only market viewer.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Broad trigger phrases like generic finance or trading recommendation terms can cause the skill to activate for requests outside its narrow intended scope. Because this skill includes network access and credential-related setup instructions, over-triggering increases the chance of unnecessary external calls or prompting users toward sensitive account operations in unrelated contexts.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The instructions establish persistent session/authentication material by having the user generate an API key and store the associated private key for repeated reuse. Persistent credentials increase blast radius if the host, agent runtime, or other skills can access the stored files, especially given the skill's broad triggers and missing explicit permission boundaries.

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

For portfolio access (RSA key signing required):

  1. Go to kalshi.com/account/profile
  2. Create new API key → save the Key ID and download the private key
  3. Store credentials:
bash

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SKILL.md (reported line 33)May include surrounding context.

bash
mkdir -p ~/.kalshi
mv ~/Downloads/your-key-file.txt ~/.kalshi/private_key.pem
chmod 600 ~/.kalshi/private_key.pem
  1. Create ~/.kalshi/credentials.json:

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api.md (reported line 3)May include surrounding context.

md
from typing import Optional
import requests

BASE_URL = "https://api.elections.kalshi.com/trade-api/v2"

def api_get(endpoint: str, params: Optional[dict] = None) -> dict:
    """Make unauthenticated GET request to Kalshi API."""

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api.md (reported line 136)May include surrounding context.

md
from typing import Optional
import requests

BASE_URL = "https://api.elections.kalshi.com/trade-api/v2"

def api_get(endpoint: str, params: Optional[dict] = None) -> dict:
    """Make unauthenticated GET request to Kalshi API."""

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/kalshi_markets.py (reported line 14)May include surrounding context.

python
from typing import Optional
import requests

BASE_URL = "https://api.elections.kalshi.com/trade-api/v2"

def api_get(endpoint: str, params: Optional[dict] = None) -> dict:
    """Make unauthenticated GET request to Kalshi API."""

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/kalshi_portfolio.py (reported line 57)May include surrounding context.

python
from typing import Optional
import requests

BASE_URL = "https://api.elections.kalshi.com/trade-api/v2"

def api_get(endpoint: str, params: Optional[dict] = None) -> dict:
    """Make unauthenticated GET request to Kalshi API."""

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code performs 'high-certainty, high-payoff opportunity' analysis and later surfaces ranked 'opportunities' to the user, which could materially influence financial decisions. The file does not include any user-facing warning or disclaimer that the output is informational only and may be inaccurate or unsuitable for trading decisions.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/kalshi_portfolio.py (reported line 39)May include surrounding context.

python
creds = load_credentials()
    if not creds:
        print(f"Error: No credentials found at {CREDENTIALS_PATH}")
        print("\nCreate credentials file:")
        print(json.dumps({
            "api_key_id": "your-key-id",
            "private_key_path": "~/.kalshi/private_key.pem"

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is described as read-only, but this file includes an interactive setup flow that collects API credentials and writes them to disk. That expands the trust boundary beyond simple data viewing and can mislead users into supplying sensitive secrets to a skill they would reasonably expect not to modify local state.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Interactive credential collection and local secret configuration are broader than the stated viewing/analysis purpose, which creates unnecessary secret-handling risk. Even if intended for convenience, asking users to paste key material metadata and persisting auth configuration increases exposure if the skill or environment is later compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This markdown file includes example code that reads a private key PEM file for API authentication. While the file notes that authentication is required, it does not warn users that they are handling sensitive credential material that should be stored and accessed securely.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.