Back to skill

Security audit

Polymarket Sniper Bot (Standalone)

Security checks for vulnerabilities and agentic risk

Overview

This is a real-money autonomous trading skill with several unsafe controls and documentation mismatches that users should review before installing.

Review this skill carefully before installing. Use only a burner wallet with limited funds, keep live trading disabled until you verify the actual code path, remove the fabricated momentum fallback, bind the dashboard to localhost or add authentication, pin dependencies in a virtual environment, and do not set PRO_LICENSE_KEY or LICENSE_SERVER unless you trust and understand the license validation service.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/polymarket.py:146
Finding
Fabricated Momentum Data Can Trigger Live Financial Trades<![CDATA[ ## Vulnerability Details **File Location**: `scripts/polymarket.py:146-170`, `scripts/polymarket.py:256-267` **Vulnerability Type**: Fail-open trading logic using fabricated market data **Risk Level**: High ### Vulnerable Code ```python def calculate_momentum(market_id): # Fetch price history from CLOB API try: # Get candles (15m resolution = 900 seconds) end = int(time.time()) start = end - (900 * 5) path = f"/prices/history?market={market_id}&interval=15m&start={start}&end={end}" headers = get_api_headers("GET", path) res = requests.get(f"{CLOB_API}{path}", headers=headers) if res.status_code == 200: prices = res.json() if len(prices) >= 3: p_now = float(prices[-1].get('price', 0)) p_old = float(prices[-3].get('price', 0)) if p_old > 0: momentum = (p_now - p_old) / p_old log_event("DEBUG", "STRATEGY", f"Market {market_id}: Price now {p_now}, 3p ago {p_old}, Mom {momentum:.4f}") return momentum # DEMO FALLBACK: If real data isn't available for this market, we mock a 3% gain # to show the user the order logic triggering. log_event("DEBUG", "DEMO", f"Mocking 3% momentum for demo: Market {market_id}") return 0.03 except Exception as e: log_event("ERROR", "STRATEGY", f"Momentum calc failed: {str(e)}") return 0.0 ``` ```python def execute_scan(): log_event("INFO", "SCAN", "Starting momentum scan loop...") markets = scan_markets() for market in markets: m_id = market.get('id') mom = calculate_momentum(m_id) if mom > 0.02: place_order(m_id, "YES") elif mom < -0.02: place_order(m_id, "NO") log_event("INFO", "SCAN", f"Scan finished. Analyzed {len(markets)} markets.") ``` ### Technical Analysis When the price-history API does not prov ...[truncated 2152 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the fabricated `0.03` fallback from all production paths. 2. Fail closed by returning `None` when market data is unavailable, incomplete, stale, malformed, or inconsistent. 3. Permit mock signals only behind an explicit simulation-only control that cannot coexist with live execution. 4. Before trading, validate: - Minimum candle count. - Candle timestamps and ordering. - Price range and numeric type. - Market and token identity. - Data freshness. 5. Require multiple independent checks before order submission, including order-book liquidity and maximum slippage. 6. Add per-order, per-scan, and daily spending limits. 7. Add tests proving that missing, empty, malformed, and stale market data can never invoke `place_order()` in live mode. 8. Consider requiring explicit operator confirmation when transitioning from simulation to live execution. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/polymarket.py:15
Finding
Undocumented Network License Response Controls Live Trading<![CDATA[ ## Vulnerability Details **File Location**: `scripts/polymarket.py:15-40`; conflicting documentation at `DEPLOYMENT.md:32-40` and `TROUBLESHOOTING.md:21-23` **Vulnerability Type**: Unsafe and misleading live-mode authorization control **Risk Level**: High ### Vulnerable Code ```python # --- License Validation --- LICENSE_SERVER = os.getenv("LICENSE_SERVER", "http://localhost:8080") PRO_LICENSE_KEY = os.getenv("PRO_LICENSE_KEY", "") def validate_pro_license(): if not PRO_LICENSE_KEY: return False try: resp = requests.post( f"{LICENSE_SERVER}/api/validate", json={"key": PRO_LICENSE_KEY, "product": "polymarket-sniper-pro"}, timeout=5 ) if resp.status_code == 200: data = resp.json() return data.get("valid", False) except Exception as e: log_event("WARN", "LICENSE", f"License check failed: {str(e)}") return False IS_LIVE = validate_pro_license() if IS_LIVE: log_event("INFO", "LICENSE", "✅ Pro license validated. Live trading ENABLED.") else: log_event("INFO", "LICENSE", "⏸️ No valid Pro license. Running in SIMULATION mode.") ``` The deployment documentation describes a different control: ```text 3. Set `live_trading: true` in your configuration (or simply ensure simulation mode is disabled). ``` The troubleshooting documentation instead states: ```text Add `pro_mode: true` (YAML boolean) to `config.yaml` and restart the bot. ``` Neither documented configuration value is consulted by the implementation. ### Technical Analysis The effective live-trading state is determined at module import by an environment-selected license server response. The documented `live_trading` and `pro_mode` settings are ignored. As a result, operators cannot reliably determine or control real-money execution using the published deployment procedure. A server returning HTTP 200 with `{"valid": true}` grants the process access to the live order pat ...[truncated 1632 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define one authoritative, documented, fail-closed live-trading setting. 2. Require both an explicit local configuration value and successful license validation before enabling live trading. 3. Do not perform network-dependent activation during module import. 4. Require a deliberate startup action or operator confirmation for live mode. 5. Print and log the effective trading mode and the controls that enabled it before any scan begins. 6. Reject contradictory or obsolete settings rather than silently ignoring them. 7. Authenticate license responses and bind them to the expected product, account, expiration, and server identity. 8. Add tests proving that live execution is impossible unless every required control is explicitly enabled. 9. Update `DEPLOYMENT.md`, `TROUBLESHOOTING.md`, and `SKILL.md` so they describe the implementation accurately. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/polymarket.py:16
Finding
License Credential Can Be Transmitted to an Arbitrary Plaintext Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/polymarket.py:16-26` **Vulnerability Type**: Sensitive credential transmission over an unrestricted network destination **Risk Level**: Medium ### Vulnerable Code ```python LICENSE_SERVER = os.getenv("LICENSE_SERVER", "http://localhost:8080") PRO_LICENSE_KEY = os.getenv("PRO_LICENSE_KEY", "") def validate_pro_license(): if not PRO_LICENSE_KEY: return False try: resp = requests.post( f"{LICENSE_SERVER}/api/validate", json={"key": PRO_LICENSE_KEY, "product": "polymarket-sniper-pro"}, timeout=5 ) ``` ### Technical Analysis The reusable `PRO_LICENSE_KEY` is placed directly in a JSON request and sent to a URL entirely controlled by the `LICENSE_SERVER` environment variable. The implementation does not enforce HTTPS, constrain the hostname to an approved service, reject redirects, or prevent transmission to an untrusted destination. The default endpoint uses plaintext HTTP. Although it points to localhost by default, environment configuration can redirect the request to any HTTP or HTTPS host. The network disclosure is also not documented in the Skill description or deployment instructions. This is the confirmed sensitive network flow identified by the pre-scan. It is not evidence of a hardcoded attacker-controlled exfiltration server, but the unrestricted destination and plaintext support create an exfiltration opportunity if the environment or endpoint is manipulated. ### Attack Path 1. A reusable license key is supplied through `PRO_LICENSE_KEY`. 2. An attacker, compromised launcher, deployment template, or configuration error sets `LICENSE_SERVER` to an attacker-controlled URL or an insecure remote HTTP endpoint. 3. The module is imported or executed. 4. `validate_pro_license()` sends the full license key in the request body. 5. The remote endpoint records and reuses the credential. Where plaintext HTTP is used across a non ...[truncated 600 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a fixed, documented HTTPS license-service origin. 2. Reject plaintext HTTP, unexpected ports, IP literals, embedded credentials, and unapproved hostnames. 3. Disable redirects or validate every redirect destination before forwarding sensitive data. 4. Authenticate the server using standard certificate verification and, where appropriate, certificate or public-key pinning. 5. Replace reusable license-key transmission with a challenge-response protocol or short-lived scoped token. 6. Keep license validation separate from live-trading authorization. 7. Document exactly what data is transmitted, when it is sent, and to which service. 8. Ensure errors and logs never contain the license key. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/dashboard.py:13
Finding
Unauthenticated Trading Dashboard Is Exposed on All Network Interfaces<![CDATA[ ## Vulnerability Details **File Location**: `scripts/dashboard.py:13-31` **Vulnerability Type**: Missing authentication and unsafe network binding **Risk Level**: Medium ### Vulnerable Code ```python @app.route('/') def index(): if not os.path.exists(DB_NAME): return "Database not initialized. Please run scripts/bootstrap.sh first." conn = get_db_connection() # Recent 50 positions, 100 logs positions = conn.execute('SELECT * FROM positions ORDER BY timestamp DESC LIMIT 50').fetchall() logs = conn.execute('SELECT * FROM logs ORDER BY timestamp DESC LIMIT 100').fetchall() heartbeats = conn.execute('SELECT * FROM heartbeats ORDER BY timestamp DESC LIMIT 5').fetchall() conn.close() return render_template('index.html', positions=positions, logs=logs, heartbeats=heartbeats) if __name__ == '__main__': print("Dashboard starting at http://0.0.0.0:5000") app.run(host='0.0.0.0', port=5000) ``` ### Technical Analysis The Flask dashboard binds to `0.0.0.0`, making it reachable through every network interface. The `/` route has no authentication or authorization check and returns recent trading positions, operational logs, and heartbeat information. The deployment guide recommends firewall restrictions, but the application itself does not enforce them. A safe default should not depend exclusively on operators correctly configuring external network controls. The route is read-only in the audited implementation, so it does not directly permit order placement or database modification. Nevertheless, it unnecessarily exceeds the minimum network exposure required for local monitoring. ### Attack Path 1. The operator starts `python3 dashboard.py`. 2. Flask listens on port 5000 on all available interfaces. 3. A firewall, cloud security group, container port mapping, or local network permits access to that port. 4. An unauthenticated remote user requests `/`. 5. The server returns recent positions, sizes, entry p ...[truncated 583 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind to `127.0.0.1` by default. 2. Require explicit configuration before listening on external interfaces. 3. Add authentication and authorization for every dashboard route. 4. Place the application behind a hardened HTTPS reverse proxy. 5. Use strong session-cookie settings, including `Secure`, `HttpOnly`, and an appropriate `SameSite` policy. 6. Restrict access by firewall, VPN, private network, or IP allowlist. 7. Minimize displayed log and financial data and redact sensitive values. 8. Disable the Flask development server for production deployment. 9. Add security tests confirming that unauthenticated requests are rejected. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/scripts/bootstrap.sh:15
Finding
Unpinned Dependencies Are Installed into the System Python Environment<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:1-4`, `scripts/scripts/bootstrap.sh:15-17` **Vulnerability Type**: Unsafe dependency installation and non-reproducible supply chain **Risk Level**: Medium ### Vulnerable Code ```text requests pyyaml flask web3 ``` ```bash # 1. Install Dependencies (Bypassing PEP 668 restrictions) echo "📦 Installing Python dependencies (bypassing system restrictions)..." pip3 install -r requirements.txt --quiet --break-system-packages ``` ### Technical Analysis None of the third-party dependencies has a pinned version or integrity hash. Each bootstrap run may therefore install a different dependency graph from the package index. The script also uses `--break-system-packages`, deliberately bypassing Python’s externally managed environment protection and installing packages into the system environment. This can overwrite or conflict with operating-system-managed packages and expands the effect of a dependency compromise beyond this Skill. No malicious or typosquatted package was confirmed in the reviewed dependency list. The vulnerability is the unsafe resolution and installation process, which provides inadequate protection against compromised releases, unexpected updates, transitive dependency changes, and environment corruption. ### Attack Path 1. A user runs `scripts/scripts/bootstrap.sh`. 2. `pip` resolves the latest available versions of all direct and transitive dependencies. 3. A compromised, vulnerable, or unexpectedly incompatible package version is selected. 4. Package build or installation logic executes with the privileges of the user running bootstrap. 5. Because system-package protections are bypassed, the installation may modify the shared Python environment. 6. Malicious or incompatible package code subsequently runs when the trading agent or dashboard imports it. ### Impact Assessment A compromised dependency may execute arbitrary code with the privileges of the bootstrap ...[truncated 507 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create and use a dedicated virtual environment instead of the system Python environment. 2. Remove `--break-system-packages`. 3. Pin every direct and transitive dependency to a reviewed version. 4. Use hash-locked requirements, such as `pip install --require-hashes`. 5. Generate a reproducible lock file using a dependency-management tool. 6. Run automated vulnerability and license scanning against the locked dependency graph. 7. Review dependency updates before deployment rather than resolving latest versions during bootstrap. 8. Avoid running the bootstrap script as root. 9. Consider using a reproducible container image with a non-root runtime user and a read-only application filesystem. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (32)

Tainted flow: 'LICENSE_SERVER' from os.getenv (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
if not PRO_LICENSE_KEY:
        return False
    try:
        resp = requests.post(
            f"{LICENSE_SERVER}/api/validate",
            json={"key": PRO_LICENSE_KEY, "product": "polymarket-sniper-pro"},
            timeout=5
Confidence
92% confidence
Finding
The code sends the PRO license key to a URL fully controlled by the LICENSE_SERVER environment variable, defaulting to insecure HTTP. An attacker who can influence environment variables or local network routing can exfiltrate the key or redirect validation traffic to an attacker-controlled host, and the lack of TLS enables interception or tampering.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Yes, this is a mismatch. The declared description presents a fully functional autonomous trading system, but the provided code chunk has no substantive behavior at all—only an empty package initializer. There are no implemented capabilities related to market access, momentum analysis, trade execution, simulation, dashboards, triggers, or external resource usage. This is a materially different actual behavior from the declared purpose.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises and likely exercises sensitive capabilities such as environment access, file reads, and network access, but does not declare any explicit tool scope or permission boundaries. In an autonomous trading context, this makes it harder for users or a hosting platform to understand and constrain what the agent can access, increasing the risk of secret exposure, unintended outbound requests, or unsafe execution paths.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill promotes autonomous live trading and a one-command bootstrap flow without prominent warnings about financial loss, real-money execution, key handling, or the consequences of enabling live mode. In this context, missing risk disclosure is dangerous because users may move from setup to live execution without understanding that the agent can place actual trades and incur immediate financial harm.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The description explicitly states that the agent 'scans ... and executes trades automatically' but provides no indication of user approval gates, disabling controls, or bounded execution conditions. In a trading context, broad autonomous-execution language increases the risk that the skill is deployed or interpreted as authorized to place real-money trades without explicit, ongoing user consent.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The natural-language metadata presents autonomous trading as a default behavior and does not mention user opt-in, supervision, or control mechanisms. Because this skill targets Polymarket on Polygon and is framed as a live trading bot, the lack of consent and control language materially raises the chance of unsafe real-fund execution, misconfiguration, or unauthorized trading activity.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README presents the project as an autonomous trading agent that scans markets and executes trades, but it does not warn users that live order placement can cause immediate financial loss or unintended trades. In a trading skill, omitting clear risk and live-execution disclosures increases the chance that a user will run the system assuming it is informational or simulated when it may place real orders.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The Quick Start tells users to execute the bootstrap script and launch the dashboard immediately, without any warning that setup may configure a live trading environment or that subsequent use could result in real market activity. Because this is an autonomous trading bot, terse execution instructions materially increase the risk of unsafe deployment before users understand configuration, credentials, or trading mode.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The manifest schedules an autonomous trading task that performs scans and executes trades every 5 minutes, but the YAML provides no explicit user-facing disclosure, confirmation gate, or risk warning that real market orders may be placed. In a trading skill, undisclosed live execution can cause financial loss if a user installs or enables the agent without fully understanding that it will trade automatically on a recurring schedule.

External Transmission

Medium
Category
Data Exfiltration
Content
if not PRO_LICENSE_KEY:
        return False
    try:
        resp = requests.post(
            f"{LICENSE_SERVER}/api/validate",
            json={"key": PRO_LICENSE_KEY, "product": "polymarket-sniper-pro"},
            timeout=5
Confidence
86% confidence
Finding
This is an external transmission of a license credential to a remote endpoint. In context, it is dangerous because the destination is environment-controlled and not restricted to secure transport, creating unnecessary exposure of a secret.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill transmits a license key to a remote service without an explicit user-facing warning in this file, and does so automatically at startup. In a security-sensitive agent context, silent outbound transmission of credentials/secrets increases privacy and trust risk, especially because the destination is configurable and defaults to plain HTTP.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
Runtime messages are sent to an arbitrary Discord webhook from configuration, which can leak trading activity, balances, market IDs, and operational status to third parties. In an autonomous trading bot, that telemetry can expose sensitive financial behavior and create an exfiltration channel if the config is altered.

External Transmission

Medium
Category
Data Exfiltration
Content
webhook = config.get("discord_webhook")
    if webhook:
        try:
            requests.post(webhook, json={"content": msg})
        except:
            pass
    print(f"Alert: {msg}")
Confidence
80% confidence
Finding
This sends alert content to an externally supplied webhook URL with no validation or disclosure. In context, alert messages may contain operational and financial information, so this creates a configurable exfiltration path.

Tainted flow: 'headers' from requests.get (line 236, network input) → requests.get (network output)

Medium
Category
Data Flow
Content
path = f"/prices/history?market={market_id}&interval=15m&start={start}&end={end}"
        headers = get_api_headers("GET", path)
        res = requests.get(f"{CLOB_API}{path}", headers=headers)
        
        if res.status_code == 200:
            prices = res.json()
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
When price history is unavailable, the bot fabricates a +3% momentum signal, which can deterministically trigger BUY orders once live mode is enabled. In an autonomous trading skill, falsifying market signals is dangerous because data outages or API failures can directly cause unauthorized or irrational real-money trades.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The bot can place real live trades automatically without an explicit confirmation gate at the point of execution. Given the autonomous context and the presence of fabricated momentum fallback logic elsewhere, the absence of a strong execution safeguard materially increases the chance of unintended financial loss.

External Transmission

Medium
Category
Data Exfiltration
Content
return

        # Submit order to CLOB
        res = requests.post(f"{CLOB_API}/orders", json=order_payload, headers=headers, timeout=10)
        if res.status_code in (200, 201):
            result = res.json()
            tx_hash = result.get('orderID') or result.get('id') or 'unknown'
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Tainted flow: 'order_payload' from requests.get (line 229, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
return

        # Submit order to CLOB
        res = requests.post(f"{CLOB_API}/orders", json=order_payload, headers=headers, timeout=10)
        if res.status_code in (200, 201):
            result = res.json()
            tx_hash = result.get('orderID') or result.get('id') or 'unknown'
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script installs dependencies with pip3 using --break-system-packages, which intentionally bypasses Python environment protections and modifies the system interpreter without prompting the user. In an autonomous trading bot context, this increases operational risk because dependency installation may destabilize the host, overwrite distro-managed packages, or make later security patching and auditing harder.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The instruction says to deploy the bot on a Linux server, which imposes a platform constraint in natural language. The file does not indicate that this is optional, nor does it explain why Linux is required, so it may conflict with the policy against forcing a specific environment without opt-in or justification.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The log_event function writes arbitrary event messages into a local database table, creating persistent records that may include operational or user-derived information. There is no confirmation, print/log disclosure to the user, or inline documentation warning that log data is stored.

Missing User Warnings

Low
Confidence
82% confidence
Finding
This code writes position records to a local SQLite database, which affects persisted user or system data. The function contains no confirmation prompt or user-facing disclosure, and this file itself does not document that the operation stores trading-related data.

Description-Behavior Mismatch

Low
Confidence
90% confidence
Finding
The manifest describes a Polymarket trading agent with dashboard, simulation mode, and live execution, but this file also contacts a separate license server and gates live trading on commercial license validation. That monetization/control-plane behavior is not an obvious implementation detail of market scanning or order execution and is absent from the stated skill description.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests
pyyaml
flask
web3
Confidence
98% confidence
Finding
The dependency list leaves requests unpinned, so installations may resolve to different versions over time, including vulnerable or breaking releases. In an autonomous trading agent, nondeterministic dependency resolution increases supply-chain risk and can expose network-facing code to known library flaws.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding
requests has multiple known advisories, and because no version is pinned, there is no way to verify whether deployments avoid affected releases. For a network-connected autonomous agent, this uncertainty is dangerous because HTTP handling may touch APIs, credentials, and remote content continuously.

Static analysis

No suspicious patterns detected.