Back to skill

Security audit

Kalshi Odds Scanner Pro

Security checks for vulnerabilities and agentic risk

Overview

This is a real-money trading skill that is mostly coherent with its purpose, but it can place live Kalshi orders with minimal safeguards and ships a hardcoded Odds API key.

Install only if you are comfortable reviewing and editing the script first. Replace the hardcoded Odds API and Kalshi identifiers, use a dedicated low-balance Kalshi account or strict limits, avoid `--buy` until you have manually reviewed the plays, and install dependencies in an isolated environment with pinned versions.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
odds_scanner.py:30
Finding

Hardcoded Odds API Credential Exposed in Source Code

Content
View full analysis

Vulnerability Details

File Location: odds_scanner.py, lines 30 and 83-86
Vulnerability Type: Hardcoded secret and credential disclosure
Risk Level: High

Vulnerable Code

python
ODDS_API_KEY = "a977eadc1440ca4b073a6158f52f796a"

The credential is subsequently transmitted as a URL query parameter:

python
url = (f"https://api.the-odds-api.com/v4/sports/{sport_key}/odds/"
       f"?apiKey={ODDS_API_KEY}&regions=us&markets=h2h&oddsFormat=decimal")
req = urllib.request.Request(url, headers={"User-Agent": "ClawdipusRex/1.0"})

Technical Analysis

The source contains a non-placeholder Odds API credential. Anyone who can read or download the Skill can extract and reuse it without authorization.

The key is also included in the request URL rather than an authentication header. Although the request destination, api.the-odds-api.com, is consistent with the Skill's declared odds-scanning functionality and is not an unrelated exfiltration endpoint, query-string credentials may be captured in application logs, proxy logs, monitoring systems, browser or debugging histories, and error reports.

Embedding the credential is unnecessary for the declared functionality. The Skill can instead obtain a user-provided credential from an environment variable or protected configuration file. The current implementation therefore exceeds the minimum secret exposure necessary to perform the task.

Attack Path

  1. An attacker obtains the distributed Skill package or gains read access to its source.
  2. The attacker reads odds_scanner.py and extracts the plaintext API key from line 30.
  3. The attacker submits requests directly to The Odds API using the exposed credential.
  4. Requests are attributed to the credential owner's account.
  5. The attacker can exhaust the account's request quota and may cause billing or service disruption, depending on the associated account plan.
  6. Additional c ...[truncated 924 chars]
Remediation
View remediation

Remediation Suggestions

  1. Immediately revoke and rotate the exposed Odds API key.

  2. Remove the key from source code and repository history.

  3. Load the credential from an environment variable, for example:

    python
    ODDS_API_KEY = os.environ.get("ODDS_API_KEY")
    if not ODDS_API_KEY:
        raise RuntimeError("ODDS_API_KEY is required")
    
  4. Alternatively, use a user-owned configuration file with restrictive filesystem permissions and ensure it is excluded from version control.

  5. If The Odds API supports header-based authentication, send the key through the documented authentication header rather than the URL query string.

  6. Configure proxies, telemetry, and error handlers to redact authentication values and URL query parameters.

  7. Add automated secret scanning to CI and pre-commit checks.

  8. Update SKILL.md so users must provide their own API credential instead of receiving an embedded credential.

T08 · Insecure Dependencies

Note
Location
SKILL.md:81
Finding

Unpinned Third-Party Dependency Installation

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 81-86
Vulnerability Type: Unpinned dependency and non-reproducible installation
Risk Level: Low

Vulnerable Code

markdown
## Requirements

- Python 3.9+
- `cryptography` library: `pip install cryptography`
- The Odds API key (free tier: 500 requests/month)
- Kalshi account with API access

Technical Analysis

The installation instructions direct users to install cryptography without a version constraint, lock file, integrity hash, or isolated environment. The package name and expected PyPI source are not suspicious, and the audit found no evidence that the project intentionally retrieves a malicious package.

Nevertheless, the command resolves to whichever package release and transitive dependencies are available at installation time. This makes installations non-reproducible and prevents users from reliably installing the same reviewed dependency set. A future compromised, incompatible, or unexpectedly changed release could affect installation or runtime behavior.

Because cryptography handles the user's Kalshi private key and creates authenticated request signatures, dependency integrity is particularly important.

Attack Path

  1. A user follows the documented pip install cryptography instruction.
  2. The package manager resolves the latest available release and its transitive dependencies at that time.
  3. If a selected release or dependency is compromised upstream, malicious code may execute during installation, import, or runtime.
  4. Since odds_scanner.py imports the library while loading and using the Kalshi private key, compromised dependency code could potentially access that key or interfere with request signing.
  5. An incompatible but non-malicious update could alternatively cause runtime failure and prevent scanning or trading.

This is a supply-chain hardening deficiency rather than evidence of an active maliciou ...[truncated 596 chars]

Remediation
View remediation

Remediation Suggestions

  1. Define a reviewed version or compatible version range for cryptography.
  2. Provide a dependency file such as requirements.txt or pyproject.toml.
  3. Generate and distribute a lock file containing exact versions.
  4. Use package hashes where supported, such as pip's --require-hashes mode.
  5. Recommend installation in a dedicated virtual environment.
  6. Periodically review pinned versions for security advisories and update them through a controlled process.
  7. Document the trusted package index explicitly and avoid unreviewed alternative indexes.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (6)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

When --buy is supplied, the script proceeds directly to execute_plays(all_plays) without any confirmation prompt, dry-run interlock, or secondary approval. Because the code already has embedded API credentials and loads a signing key, this can trigger immediate live trades from a single command invocation, creating direct financial loss risk if inputs, matching logic, or environment assumptions are wrong.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly provides a --buy mode that places real trades on Kalshi using the user's configured API credentials, but the documentation presents it as a normal usage example without a prominent warning about financial execution and loss risk. In a trading skill, this omission is dangerous because a user may run the command during testing or exploration and unknowingly authorize live market orders with real funds.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The top-level docstring presents the script as a scanner/comparison tool, but it also supports live order placement via the --buy flag. In a trading context, under-describing write/execution capability is dangerous because a user or agent may treat it as read-only analysis and invoke it in an environment with live credentials, leading to unintended financial transactions.

Content

No source excerpt is available for this finding.

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 · odds_scanner.py (reported line 73)May include surrounding context.

python
"Accept": "application/json", "Content-Type": "application/json"}
    data = json.dumps(body).encode() if body else None
    req = urllib.request.Request(
        f"https://api.elections.kalshi.com/trade-api/v2{endpoint}",
        data=data, headers=headers, method=method.upper()
    )
    try:

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 · odds_scanner.py (reported line 84)May include surrounding context.

python
def get_odds(sport_key):
    """Fetch sportsbook lines from The Odds API."""
    url = (f"https://api.the-odds-api.com/v4/sports/{sport_key}/odds/"
           f"?apiKey={ODDS_API_KEY}&regions=us&markets=h2h&oddsFormat=decimal")
    req = urllib.request.Request(url, headers={"User-Agent": "ClawdipusRex/1.0"})
    try:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The helper appends ensemble results to TRADE_LOG.md whenever the file exists, creating a persistent record of trading activity. The function has no user-facing print, prompt, or nearby warning indicating that local files will be modified as a side effect of running the scanner.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.