Back to skill

Security audit

polymarketz

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a Polymarket data CLI, but it asks for and persistently stores a Polygon private key even though live trading is only stubbed out.

Install only if you want a Polymarket market-data CLI and are comfortable reviewing the code yourself. Do not enter a funded wallet's private key into this skill; use a fresh empty wallet at minimum, and treat any key saved by this version as exposed enough to rotate before funding it.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/polymarket.py:548
Finding
Polygon Private Key Stored in Plaintext and Entered Through an Echoing Prompt## Vulnerability Details **File Location**: `scripts/polymarket.py:548-562` **Vulnerability Type**: Plaintext storage and insecure collection of sensitive wallet credentials **Risk Level**: High ### Vulnerable Code ```python pk = input(" Enter your Polygon private key (hex): ").strip() if not pk: print(" Aborted.") return # Remove 0x prefix if present if pk.startswith("0x"): pk = pk[2:] WALLET_PATH.parent.mkdir(parents=True, exist_ok=True) config = {"private_key": pk} with open(WALLET_PATH, "w") as f: json.dump(config, f, indent=2) os.chmod(WALLET_PATH, 0o600) ``` The stored credential is subsequently loaded in full by the following helper at `scripts/polymarket.py:529-535`: ```python def _load_wallet(): """Load wallet config.""" if not WALLET_PATH.exists(): print("No wallet configured. Run: python3 polymarket.py wallet-setup", file=sys.stderr) sys.exit(1) with open(WALLET_PATH) as f: return json.load(f) ``` ### Technical Analysis The wallet setup command collects a Polygon private key using `input()`. Terminal input is therefore displayed while the user types, exposing the key to shoulder surfing, terminal recording, screen sharing, and captured console sessions. The key is then serialized without encryption to `~/.config/polymarket/wallet.json`. Setting the completed file to mode `0600` restricts access by other local user accounts, but it does not protect the key from: - Malicious or compromised processes running under the same user account. - Filesystem, workstation, or user-account compromise. - Backup, synchronization, snapshot, or diagnostic systems that capture the file. - Exposure during the interval between file creation and the subsequent `chmod`. - Accidental disclosure through copying or support collection. The implementation also loads the complete wallet object for placeholder commands such as `balance` and a ...[truncated 1980 chars]
Remediation
## Remediation Suggestions 1. **Do not store raw private keys in plaintext.** Prefer a hardware wallet, external signer, OS credential manager, or encrypted keystore using a well-reviewed wallet library. 2. **Use hidden credential entry.** Replace `input()` with `getpass.getpass()` so the private key is not echoed: ```python from getpass import getpass pk = getpass(" Enter your Polygon private key (hex): ").strip() ``` 3. **Separate public identity from signing credentials.** Store only the public wallet address in ordinary configuration. Retrieve private signing material only when an operation actually requires a signature. 4. **Remove unnecessary wallet loading.** The placeholder `balance` and `orders` commands should not call `_load_wallet()` merely to establish that configuration exists. They should load a public-address-only configuration or request an address explicitly. 5. **Create sensitive files atomically with restrictive permissions.** If a local encrypted keystore is retained, create it with mode `0600` from the outset rather than applying permissions only after writing. 6. **Minimize secret lifetime in memory.** Load signing credentials immediately before signing, avoid logging or copying them, and release references as soon as practical. 7. **Validate imported key material safely.** Use a trusted wallet library to validate and derive the corresponding public address without printing or transmitting the private key. 8. **Document migration and rotation.** Existing users should move funds to a newly generated key if they believe the plaintext file or visible setup session may have been exposed, then securely delete the old credential file and affected backups.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill description understates or misstates sensitive behavior by framing the tool primarily as a browsing/analysis skill while also documenting local storage of a Polygon private key and trade-related operations. Misrepresentation of credential handling is dangerous because users may invoke the skill expecting harmless read-only behavior, yet be prompted to create or store highly sensitive secrets on disk. In a financial trading context, that mismatch materially increases risk of credential theft, unintended monetary loss, and unsafe trust decisions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises and documents shell execution, network access, and local file writes but does not declare any tool scope such as permissions or allowed-tools. That creates an authorization gap where a host agent may grant broader capabilities than a reviewer or user expects, especially since the skill also includes wallet setup that writes sensitive material to disk. In a trading skill context, undeclared network and file-write access is more dangerous because it can interact with external APIs and persist credentials.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill interactively collects a Polygon private key and stores it in plaintext JSON on disk. Even with restrictive file permissions, plaintext key storage materially increases the chance of credential theft from local compromise, backups, syncing tools, shell observation, or accidental disclosure; in a trading skill, compromise of this key can directly lead to loss of funds.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest describes a skill that can 'execute trades', while the implemented trading-related commands only print previews, guidance, or placeholders indicating that CLOB authentication is required. Even with --confirm, cmd_trade does not submit an order, and cancel/cancel-all similarly do not invoke any trading API or state-changing operation.

Description-Behavior Mismatch

Low
Confidence
84% confidence
Finding
The manifest states that read-only commands work instantly with zero setup, but cmd_balance requires a locally configured wallet and still only returns a placeholder message instead of actual balance data. This creates a smaller but meaningful mismatch between the advertised readiness of account-related read-only features and their implementation.

Static analysis

No suspicious patterns detected.