Back to skill

Security audit

Polymarket Spread Sniper

Security checks for vulnerabilities and agentic risk

Overview

This trading skill is not clearly malicious, but it needs review because its packaged settings can spend far more than the documented limits and its helper scripts read a shared secrets file.

Review the configured trading limits before installing or running live mode. Use a narrowly scoped Simmer API key, isolate the runtime environment, avoid shared .env files with unrelated secrets, and pin/review simmer-sdk before granting live trading authority.

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)

T09 · Insecure Skill Coding Practices

Error
Location
config.json:2
Finding

Committed Configuration Effectively Disables Advertised Trading Limits

Content
View full analysis
= DAILY_MAX_SPEND: log(f"\n Daily spend limit reached (${daily_state['spent']:.2f} / ${DAILY_MAX_SPEND:.2f}). Stopping.") break ``` ### Technical Analysis The committed runtime configuration overrides the documented defaults of a `$5.00` maximum position and `$100.00` daily spend cap with a `$50.00` position and a `$999,999.00` daily cap. The configured position size also exceeds the `$25.00` upper bound advertised in `clawhub.json`. Because `load_config()` loads these overrides during startup, they apply automatically without requiring an explicit user configuration change. The daily cap is consequently ineffective under ordinary use. The pre-trade check also compares only the amount already spent against the cap. It does not verify whether the proposed order would cause `spent + position_size` to exceed the cap. Even with a reasonable cap, the final order can therefore overshoot it by as much as one full position. ### Attack Path 1. A user reviews the documentation and expects the advertised `$5` position and `$100` daily limits. 2. The user starts the Skill with `--live`, or an automation system invokes live execution. 3. `load_config()` loads the committed `config.json` overrides. 4. Each scan can execute up to three `$50` orders. 5. Repeated scans continue trading because the effective daily limit is `$999,999`. 6. The bot can deploy substantially more money than the user reasonably expected from the documented safeguards. No exte ...[truncated 589 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/spread_pnl.py:27
Finding

Helper Scripts Import Every Secret from a Shared Workspace Environment File

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding

Unpinned Trading SDK Receives API Credentials and Financial Authority

Content
View full analysis
Remediation
View remediation
"] ``` 2. Use a lockfile with cryptographic hashes, such as a hash-locked requirements file generated by `pip-tools`. 3. Install only from the expected package index over TLS and disable unneeded alternate indexes. 4. Review package provenance, maintainer ownership, release signatures, and dependency changes before upgrades. 5. Update dependencies through an explicit review process rather than automatically accepting the latest release. 6. Use a narrowly scoped Simmer API credential with server-side trading limits and no permissions unrelated to this Skill. 7. Run the Skill in an isolated environment with only the required secret and minimal filesystem permissions. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (18)

Tainted flow: 'api_key' from os.environ.get (line 100, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/sim_redeem.py (reported line 65)May include surrounding context.

python
params = {"status": "resolved", "venue": venue}
    if source:
        params["source"] = source
    resp = requests.get(
        f"{BASE_URL}/api/sdk/positions",
        params=params,
        headers={"Authorization": f"Bearer {api_key}"},

Tainted flow: 'api_key' from os.environ.get (line 70, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/spread_pnl.py (reported line 53)May include surrounding context.

python
def fetch_resolved_pnl(api_key):
    """Fetch resolved spreadsniper positions via raw API for true realized P&L."""
    try:
        resp = requests.get(
            "https://api.simmer.markets/api/sdk/positions",
            params={"status": "resolved", "venue": "sim", "source": SKILL_SOURCE},
            headers={"Authorization": f"Bearer {api_key}"},

Tainted flow: 'api_key' from os.environ.get (line 156, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · spread_sniper.py (reported line 326)May include surrounding context.

python
return 0

    try:
        resp = _req.get(
            "https://api.simmer.markets/api/sdk/positions",
            params={"status": "active", "venue": VENUE, "source": TRADE_SOURCE},
            headers={"Authorization": f"Bearer {api_key}"},

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

A second documented mismatch indicates the implementation may not perform the advertised market scanning, price comparison, or trade execution at all, instead acting primarily as a Simmer portfolio reporting and logging tool. Mislabeling a skill's purpose can conceal unexpected network access, credential use, and persistent local logging, increasing the risk of unauthorized data exposure or unintended account interactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

A second documented mismatch indicates the implementation may not perform the advertised market scanning, price comparison, or trade execution at all, instead acting primarily as a Simmer portfolio reporting and logging tool. Mislabeling a skill's purpose can conceal unexpected network access, credential use, and persistent local logging, increasing the risk of unauthorized data exposure or unintended account interactions.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

python
python scripts/sim_redeem.py --source sdk:spreadsniper   # filter by source

Cron (every 15 min):
    */15 * * * * source ~/.openclaw/workspace/.env && \\
        python3 ~/.openclaw/workspace/skills/polymarket-spread-sniper/scripts/sim_redeem.py --live \\
        >> ~/.openclaw/workspace/skills/sim_redeem.log 2>&1
"""

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The code explicitly locates and parses a shared workspace .env file, which is credential access behavior and grants the script direct access to secrets outside its immediate directory. In the context of a trading skill advertised as a pure algorithm, this hidden credential harvesting path is more dangerous because it enables account actions and broadens trust assumptions across the workspace.

Content

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

python
def _load_env():
    env_path = Path(__file__).resolve().parents[4] / ".env"
    if env_path.exists():
        for line in env_path.read_text().splitlines():
            line = line.strip()

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Reading a .env file from a distant ancestor directory is a form of credential access that exceeds the narrow operational need of this reporting script. In a shared repository or agent environment, it may expose unrelated secrets to this code path and enables silent secret harvesting if the script is repurposed or later modified.

Content

Scanner excerpt · scripts/spread_pnl.py (reported line 29)May include surrounding context.

python
def _load_env():
    env_path = Path(__file__).resolve().parents[4] / ".env"
    if env_path.exists():
        for line in env_path.read_text().splitlines():
            line = line.strip()

Missing User Warnings

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

Real-money trading is enabled solely by passing --live, with no interactive confirmation, secondary approval, or environment guard. In an automated or scripted environment, a typo, wrapper misconfiguration, or malicious invocation could trigger unintended live trades and immediate financial loss.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares no explicit tool or permission scope while its documented behavior and referenced files imply use of environment variables, network access, and local file read/write. In an agent ecosystem, missing scope declarations weaken policy enforcement and user visibility, allowing a skill to access sensitive credentials or persist data beyond what a reviewer expects.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script reads a workspace-level .env file directly and extracts SIMMER_API_KEY, giving it account-access capability beyond a pure algorithmic strategy. This broad credential-loading pattern increases blast radius because any code in the skill can silently inherit account credentials without clear user consent or least-privilege boundaries.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script can perform live settlement operations against the user's SIM account via client.redeem(...), which is broader than the skill's stated spread-sniping behavior. Even if limited to SIM, this expands the skill from analysis/trading logic into account mutation, increasing operational risk and creating a hidden capability users may not expect from the manifest.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script persistently appends portfolio snapshots to a local log file, creating an accumulating record of balances, P&L, and trading activity. Even though this is local rather than remote exfiltration, it stores sensitive financial telemetry not clearly disclosed by the skill description and may expose data to other users, processes, backups, or accidental commits.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script walks up four parent directories and loads a top-level .env file, which broadens its credential access beyond the immediate skill scope. In a multi-skill or shared workspace, this can cause the script to ingest secrets unrelated to this tool, violating least privilege and increasing the blast radius if the file path or environment is manipulated.

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 · scripts/spread_pnl.py (reported line 54)May include surrounding context.

python
"""Fetch resolved spreadsniper positions via raw API for true realized P&L."""
    try:
        resp = requests.get(
            "https://api.simmer.markets/api/sdk/positions",
            params={"status": "resolved", "venue": "sim", "source": SKILL_SOURCE},
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=15,

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

python
"""Fetch resolved spreadsniper positions via raw API for true realized P&L."""
    try:
        resp = requests.get(
            "https://api.simmer.markets/api/sdk/positions",
            params={"status": "resolved", "venue": "sim", "source": SKILL_SOURCE},
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=15,

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The top-level documentation describes a spread-sniping strategy that buys the underpriced side and sells when the spread closes or price returns to fair value. In practice, the exit path uses portfolio position data and a time-stop, without recalculating the original AMM-vs-CLOB spread or fair value convergence. That makes the documented strategy materially different from the implemented one.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring for check_exits says take-profit triggers when the current AMM price has converged toward the CLOB by a fraction of the entry edge. However, the implementation never fetches AMM or CLOB data during exit checks; it computes take-profit solely from current_probability versus entry_price. This is an active contradiction in the documented trading intent, not just an omitted detail.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.