Back to skill

Security audit

Polymarket CLI & Arb Scanner

Security checks for vulnerabilities and agentic risk

Overview

This Polymarket trading skill is useful and mostly transparent about its purpose, but it needs Review because it includes unsafe installation paths and a helper script with local command-injection risk.

Install only after reviewing or replacing the installer with pinned, verified CLI artifacts. Prefer read-only commands unless you intentionally want an agent to trade, approve contracts, bridge funds, or import wallets. Do not paste real private keys into command lines, and avoid running scripts/expiry-arb.ts with untrusted query text until the shell interpolation is fixed.

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

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/install.sh:7
Finding
Unverified Remote Installation Scripts Are Executed Directly by a Shell<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:15`, `scripts/install.sh:7`, and `scripts/install.sh:19` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Vulnerable Code `SKILL.md:15`: ```bash curl -sSL https://raw.githubusercontent.com/Polymarket/polymarket-cli/main/install.sh | sh ``` `scripts/install.sh:7`: ```bash if curl -sSL https://raw.githubusercontent.com/Polymarket/polymarket-cli/main/install.sh | sh 2>/dev/null; then ``` `scripts/install.sh:19`: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ``` ### Technical Analysis These commands download scripts from external URLs and pass the responses directly to a shell. The downloaded content is executed before it can be inspected, and no cryptographic signature, checksum, immutable commit, or release version is verified. The Polymarket installer URL follows the mutable `main` branch. Consequently, the effective code executed by this Skill can change after the reviewed package has been published. HTTPS protects the connection in transit but does not protect against compromise of the upstream repository, hosting account, release process, or authorized publisher credentials. The Rust installer is retrieved from a recognized project domain and explicitly requires HTTPS and TLS 1.2, but it still has the same execute-before-verification weakness. This behavior exceeds the minimum privileges required for read-only market browsing and price analysis. Installation should be an explicit, independently verified prerequisite rather than an automatic remote-code execution path. ### Attack Path 1. A user or Agent follows the prerequisite instructions or runs `scripts/install.sh`. 2. The shell retrieves the current response from the external installer URL. 3. An attacker compromises the upstream repository, hosting account, publishing process, or another trusted component controlling the response. 4. The attacker replac ...[truncated 992 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove every `curl | sh` installation path from both the documentation and installer. 2. Download the installer or release artifact into a newly created temporary directory without executing it. 3. Pin the dependency to an immutable release version or commit rather than `main`. 4. Publish a SHA-256 checksum through a separately protected release channel and verify it before execution. 5. Prefer publisher-signed release artifacts and verify the signature against a bundled, trusted public key. 6. Display the selected version and source to the user and require explicit approval before installation. 7. Fail closed if signature, checksum, or version verification cannot be completed. 8. Do not recommend running installation as root. 9. Treat Rust as a documented prerequisite, or install it through the operating system's trusted package manager rather than executing an unverified bootstrap response. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/install.sh:23
Finding
Mutable and Unverified Upstream Source Is Built and Installed<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh:23-25` **Vulnerability Type**: Unpinned and unverified source dependency **Risk Level**: High ### Vulnerable Code ```bash git clone --depth 1 https://github.com/Polymarket/polymarket-cli.git "$TMPDIR/polymarket-cli" cd "$TMPDIR/polymarket-cli" cargo install --path . ``` ### Technical Analysis The fallback installation path clones the current default branch of the upstream repository without pinning a tag or commit. It does not verify a signed tag, commit signature, source archive checksum, or release attestation. The cloned source is immediately passed to Cargo. Cargo can compile and execute dependency build scripts during installation, so this is not limited to installing a final binary: attacker-controlled source or dependency metadata can cause code execution during the build itself. A shallow clone does not provide security or reproducibility. It merely reduces clone history and still retrieves mutable upstream state. The absence of an explicit `--locked` option also weakens dependency reproducibility if the project has a lockfile whose resolution would otherwise change. ### Attack Path 1. The prebuilt installation path fails or produces an incompatible executable. 2. `scripts/install.sh` enters the source-build fallback. 3. An attacker compromises the upstream default branch, an upstream dependency, or the associated release workflow. 4. The script clones the attacker-controlled current repository state. 5. `cargo install --path .` processes the malicious manifest, source, or build script. 6. Build-time code executes and a compromised `polymarket` binary is installed into the user's executable environment. 7. Later legitimate-looking CLI calls execute the compromised binary. ### Impact Assessment Build scripts execute with the privileges of the invoking user and can read or modify user-accessible files, environment variables, configuration, and credentials. A malicious insta ...[truncated 323 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the repository to a specific audited commit or signed release tag. 2. Fetch the expected commit explicitly and verify that the checked-out `HEAD` equals the hard-coded commit identifier. 3. Verify a signed tag or commit against a documented trusted maintainer key. 4. Prefer a versioned source archive with a hard-coded checksum over cloning a mutable branch. 5. Commit and review the Cargo lockfile, then build using `cargo install --locked --path .`. 6. Audit dependencies and Cargo build scripts before allowing installation. 7. Build in a restricted environment without wallet files, unrelated credentials, or broad filesystem access. 8. Avoid silently entering the source-build fallback. Report the failure and require explicit user confirmation before compiling upstream code. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/expiry-arb.ts:58
Finding
User-Controlled Market Query Allows Shell Command Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/expiry-arb.ts:58-59` and `scripts/expiry-arb.ts:70-72` **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code User-controlled input is assigned to `query`: ```ts } else if (!args[i].startsWith("--")) { query = args[i]; } ``` It is then interpolated into a Bash command: ```ts rawOutput = execSync( `source "$HOME/.cargo/env" 2>/dev/null; polymarket -o json markets search "${query}" --limit 200`, { encoding: "utf-8", shell: "/bin/bash", maxBuffer: 50 * 1024 * 1024 } ); ``` ### Technical Analysis The script accepts a command-line argument and embeds it directly into a command string evaluated by `/bin/bash`. Surrounding the value with double quotes does not make it safe. An attacker can provide a quote to terminate the intended argument or use command substitutions such as `$(...)` or backticks, which Bash evaluates even inside double quotes. The use of a shell is unnecessary because the program only needs to invoke `polymarket` with discrete arguments. This coding pattern converts ordinary market-search text into executable shell syntax. For example, a crafted query containing command substitution can cause the substituted command to execute while Bash constructs the argument passed to `polymarket`. Exploitation does not require control over the Polymarket service; it only requires influence over the local query supplied to this script. ### Attack Path 1. An attacker persuades a user or Agent to scan a specially crafted “market query,” or otherwise controls the argument supplied to `expiry-arb.ts`. 2. The argument is stored in `query` without shell-safe handling. 3. The script constructs a command string containing that value. 4. `execSync` invokes `/bin/bash` because `shell: "/bin/bash"` is configured. 5. Bash interprets attacker-supplied command substitution, quoting, or metacharacters. 6. The injected local command executes with the privileges and envir ...[truncated 617 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `execSync` and the command string with `execFileSync` or `spawnSync`. 2. Pass every CLI argument as a separate array element so no shell parsing occurs. For example: ```ts import { execFileSync } from "node:child_process"; rawOutput = execFileSync( "polymarket", ["-o", "json", "markets", "search", query, "--limit", "200"], { encoding: "utf-8", maxBuffer: 50 * 1024 * 1024, env: { ...process.env, PATH: `${process.env.HOME}/.cargo/bin:${process.env.PATH ?? ""}`, }, } ); ``` 3. Do not use `shell: true` or specify a shell for this invocation. 4. Set the required `PATH` through the child-process environment rather than sourcing `$HOME/.cargo/env`. 5. Validate input length and reject control characters to reduce denial-of-service and logging risks, while recognizing that validation is not a substitute for eliminating shell evaluation. 6. Add regression tests using quotes, semicolons, backticks, and command-substitution strings to verify that they are passed only as literal query text. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/expiry-arb.ts:1
Finding
Unpinned npx Launcher Can Retrieve and Execute a Package at Runtime<![CDATA[ ## Vulnerability Details **File Location**: `scripts/expiry-arb.ts:1` and `scripts/expiry-arb.ts:13` **Vulnerability Type**: Unpinned runtime dependency execution **Risk Level**: Medium ### Vulnerable Code ```ts #!/usr/bin/env -S npx tsx ``` The documented invocation reinforces the same execution path: ```text Usage: npx tsx expiry-arb.ts "US strikes Iran" [--threshold 0.5] ``` ### Technical Analysis The launcher invokes `tsx` through `npx` without specifying a package version. If a suitable local executable is unavailable, `npx` can obtain the package from the configured npm registry and execute it. The audited project contains no package manifest, lockfile, pinned `tsx` version, or integrity metadata establishing which code should run. The actual behavior depends on the user's npm and `npx` version and configuration, but the launcher creates a supply-chain execution path in environments where missing packages are downloaded. A compromised package version, maintainer account, registry, or configured registry mirror could therefore introduce arbitrary code after this Skill was reviewed. ### Attack Path 1. A user executes `scripts/expiry-arb.ts` directly or follows the documented `npx tsx` invocation. 2. No trusted local `tsx` executable is available. 3. `npx` resolves `tsx` using the configured npm registry without an exact version pinned by this project. 4. The registry or package release supplies compromised code. 5. The downloaded package executes under the invoking user's account before or while running the scanner. ### Impact Assessment A compromised package executes arbitrary JavaScript with the user's normal privileges. It can access environment variables, user-readable files, project files, npm configuration, and any Polymarket or wallet-related resources accessible to that user. This finding does not establish that the genuine `tsx` package is malicious. The risk arises from allowing an unpinned, potentially remote package to becom ...[truncated 33 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a project package manifest and declare an exact reviewed version of `tsx`. 2. Commit the package-manager lockfile and enforce lockfile-based installation with integrity verification. 3. Configure installation to use a trusted registry and avoid runtime package downloads. 4. Invoke the locally installed executable, such as `./node_modules/.bin/tsx`, rather than relying on automatic `npx` resolution. 5. Alternatively, compile the TypeScript into reviewed JavaScript during a controlled build process and execute it directly with Node.js. 6. Run dependency auditing and review transitive dependencies before updating the pinned version. 7. Document dependency installation as a separate explicit step rather than allowing script startup to retrieve executable code. ]]>
Vulnerability Patterns
  • 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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (13)

Chaining Abuse

High
Category
Tool Misuse
Content
Binary must be installed. If missing:
```bash
curl -sSL https://raw.githubusercontent.com/Polymarket/polymarket-cli/main/install.sh | sh
# Or build from source:
# cargo install --path /tmp/polymarket-cli
```
Confidence
98% confidence
Finding
Using 'curl ... | sh' chains network retrieval directly into shell execution, eliminating any inspection or verification step before running code. In the context of a financial trading skill that can later manage wallets and approvals, compromise of the install path could lead to full command execution, credential theft, malicious transaction signing, or fund loss.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script interpolates the user-controlled `query` directly into a Bash command passed to `execSync(..., { shell: '/bin/bash' })`. Because the query is placed inside double quotes, shell metacharacters such as command substitution (`$(...)`), backticks, or quote-breaking payloads can trigger arbitrary command execution on the host running the skill, which is far more dangerous than the stated market-scanning purpose.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The example `polymarket wallet import 0xYOUR_PRIVATE_KEY` normalizes entering a raw private key directly on the command line without any adjacent warning about shell history, process inspection, clipboard leakage, or safer alternatives. In a trading skill that explicitly handles wallets and real assets, this can lead users to expose credentials that would allow full theft of funds and account control.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill invokes shell commands extensively, including installation, wallet management, and trading operations, but does not declare any tool restrictions such as allowed-tools or permissions. That creates an unnecessarily broad execution surface and makes it easier for an agent runtime to permit risky shell actions beyond the minimum needed for the skill.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
polymarket setup                    # Interactive wizard
# Or manually:
polymarket wallet create            # New wallet
polymarket wallet import 0xKEY...   # Import existing
polymarket approve set              # Approve contracts (needs MATIC)
```
Confidence
84% confidence
Finding
The skill instructs users to create/import wallets and states that configuration is stored in ~/.config/polymarket/config.json, indicating session or credential persistence on disk. In a multi-tool or shared environment, persisted wallet material or auth state can be reused by later sessions or other processes, leading to unauthorized trading or exposure of sensitive keys.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill documents order placement, cancellations, approvals, wallet creation/import, bridging, and on-chain token operations without prominent warnings that these actions can move funds, grant token allowances, or cause irreversible blockchain transactions. In an agent setting, this increases the risk of a user or automated workflow triggering real financial loss or unintended approvals without informed confirmation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Beyond the injection issue, the skill executes a shell using untrusted input without any clear disclosure to the user that a free-form search term will be fed into Bash. In the context of an agent skill for browsing and trading Polymarket, this mismatch increases risk because a seemingly harmless market-search request could lead to arbitrary local command execution if the input is attacker-influenced.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The installer executes remote scripts directly from the network via shell piping, both for the Polymarket CLI bootstrapper and for rustup, without pinning versions, verifying checksums/signatures, or requiring user confirmation. If the upstream content, GitHub path, DNS/TLS trust chain, or distribution channel is compromised, arbitrary code will run immediately on the host during installation.

External Script Fetching

Low
Category
Supply Chain
Content
Binary must be installed. If missing:
```bash
curl -sSL https://raw.githubusercontent.com/Polymarket/polymarket-cli/main/install.sh | sh
# Or build from source:
# cargo install --path /tmp/polymarket-cli
```
Confidence
95% confidence
Finding
The skill recommends fetching and executing an installation script directly from a remote GitHub URL. This creates a supply-chain risk because the fetched script can change over time or be tampered with, and the agent/user is instructed to trust and run it immediately.

External Script Fetching

Low
Category
Supply Chain
Content
echo "Installing Polymarket CLI..."

# Try pre-built binary first
if curl -sSL https://raw.githubusercontent.com/Polymarket/polymarket-cli/main/install.sh | sh 2>/dev/null; then
  # Verify it works (GLIBC compatibility)
  if polymarket --version 2>/dev/null; then
    echo "✅ Polymarket CLI installed (pre-built)"
Confidence
99% confidence
Finding
This line fetches an installer script from a mutable GitHub branch URL and executes it immediately with sh. That creates a direct remote code execution path during setup, and because it uses a branch reference rather than a pinned immutable artifact, the executed code can change over time without review.

External Script Fetching

Low
Category
Supply Chain
Content
# Build from source
if ! command -v cargo &>/dev/null; then
  echo "Installing Rust..."
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
  source "$HOME/.cargo/env"
fi
Confidence
95% confidence
Finding
Although rustup is a common legitimate installer, piping it directly into sh still executes unaudited remote code at install time. The risk is somewhat reduced by HTTPS and the widespread use of rustup, but compromise of the distribution endpoint or trust chain would still lead to arbitrary code execution.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/expiry-arb.ts:70