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## 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 ``` ``` **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
## 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.

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.

Credential Access

High
Category
Privilege Escalation
Content
chmod 600 ~/.kalshi/private_key.pem
```

4. Create `~/.kalshi/credentials.json`:
```json
{
  "api_key_id": "your-key-id-here",
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.

Credential Access

High
Category
Privilege Escalation
Content
except ImportError:
    HAS_SDK = False

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


def load_credentials() -> dict:
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.

Lp3

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.

Vague Triggers

Medium
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.

Session Persistence

Medium
Category
Rogue Agent
Content
For portfolio access (RSA key signing required):

1. Go to [kalshi.com/account/profile](https://kalshi.com/account/profile)
2. Create new API key → save the **Key ID** and download the **private key**
3. Store credentials:

```bash
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
mkdir -p ~/.kalshi
mv ~/Downloads/your-key-file.txt ~/.kalshi/private_key.pem
chmod 600 ~/.kalshi/private_key.pem
```

4. Create `~/.kalshi/credentials.json`:
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

External Transmission

Medium
Category
Data Exfiltration
Content
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."""
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
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."""
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
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."""
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
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."""
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
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.

Session Persistence

Medium
Category
Rogue Agent
Content
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"
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.

Description-Behavior Mismatch

Medium
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.

Context-Inappropriate Capability

Medium
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.

Missing User Warnings

Low
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.

Static analysis

No suspicious patterns detected.