Back to skill

Security audit

Polymarket Whale Copier

Security checks for vulnerabilities and agentic risk

Overview

This Polymarket trading skill asks for a wallet private key and advertises automatic trading/redeeming that the code does not actually implement.

Review carefully before installing. Do not provide a real funded wallet private key to this skill as written, and do not rely on it for automatic copy trading or redemption. If experimenting, use dry-run behavior only, use a separate low-risk wallet/address, and expect local logs plus repeated network calls to Polymarket and Polygon endpoints.

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

Warning
Location
scripts/copy_trader.py:42
Finding
Unnecessary transmission of a deterministic private-key-derived identifier<![CDATA[ ## Vulnerability Details **File Location**: `scripts/copy_trader.py:42-53`, `scripts/copy_trader.py:96-106`, and `scripts/copy_trader.py:117-125` **Vulnerability Type**: Improper handling and external disclosure of secret-derived data **Risk Level**: Medium ### Vulnerable Code ```python self.private_key = os.environ.get("POLYMARKET_KEY", "") self.our_wallet = self._derive_wallet() if self.private_key else None ``` ```python def _derive_wallet(self): """Derive wallet address from private key (simplified)""" try: # In production, use proper eth library # This is a placeholder - real implementation needs web3 return "0x" + hashlib.sha256(self.private_key.encode()).hexdigest()[:40] except: return None ``` The resulting identifier is included in requests to external services: ```python req = urllib.request.Request( "https://polygon-rpc.com", data=json.dumps(payload).encode(), headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req, timeout=10) as resp: result = json.loads(resp.read().decode()) ``` ```python def get_our_positions(self): """Get our current positions""" if not self.our_wallet: return {} url = f"https://data-api.polymarket.com/positions?user={self.our_wallet}" positions = self._fetch_json(url) or [] return {p.get("asset_id"): p for p in positions} ``` ### Technical Analysis The Skill reads `POLYMARKET_KEY`, hashes the private key with SHA-256, truncates the result to 40 hexadecimal characters, and treats that value as an Ethereum wallet address. This is not a valid Ethereum address-derivation procedure. The resulting deterministic, secret-derived identifier is subsequently transmitted to: - `https://polygon-rpc.com` as part of an `eth_call` request for a USDC balance. - `https://data-api.polymarket.com` as the `user` parameter of a positions request. The raw private key is not directly transmitted, and recovering a properly ...[truncated 2253 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all access to `POLYMARKET_KEY` until transaction signing is actually implemented. 2. Accept a separate public wallet address, such as `POLYMARKET_WALLET`, for balance and position queries. 3. Validate supplied public addresses for proper Ethereum syntax and checksum before including them in network requests. 4. If signing is later implemented, derive the public address with an audited Ethereum library rather than manually hashing the private key. 5. Keep all signing operations local and never include private keys or unnecessary secret-derived values in API requests, URLs, logs, errors, or persistent state. 6. Separate read-only monitoring from transaction execution so the default monitoring mode never requires wallet credentials. 7. Document every external endpoint and the exact public data transmitted to it. 8. Add tests confirming that read-only and dry-run modes do not access `POLYMARKET_KEY`. 9. Update `SKILL.md` to state accurately that live trading and automatic redemption are not currently implemented. ]]>
Vulnerability Patterns
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill says 'No API keys needed' while instructing the user to export a POLYMARKET_KEY private key, which is materially more sensitive than an API key. This mismatch can cause users to underestimate the sensitivity of the credential they are providing, increasing the chance of secret compromise and unauthorized trading if the key is mishandled by the skill or runtime.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill says 'No API keys needed' while instructing the user to export a POLYMARKET_KEY private key, which is materially more sensitive than an API key. This mismatch can cause users to underestimate the sensitivity of the credential they are providing, increasing the chance of secret compromise and unauthorized trading if the key is mishandled by the skill or runtime.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill says 'No API keys needed' while instructing the user to export a POLYMARKET_KEY private key, which is materially more sensitive than an API key. This mismatch can cause users to underestimate the sensitivity of the credential they are providing, increasing the chance of secret compromise and unauthorized trading if the key is mishandled by the skill or runtime.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises operational capabilities that would require access to environment variables, files, and the network, but it does not declare any explicit tool scope or permissions boundaries. In a trading skill that handles a private key and automation, missing scope declarations increases the risk of overbroad access, secret exposure, or unintended file/network operations if the skill is executed in a permissive runtime.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The top-level documentation states that the script will copy trades automatically, but the operational code does not perform live execution. In a trading skill, misleading capability claims can directly influence user behavior, causing them to rely on nonexistent automation, hedging, or risk controls while real trades never occur.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The skill metadata and CLI suggest it can automatically mirror trades, but in live mode the code explicitly refuses to execute and only logs a placeholder. In a financial trading context, this is a security-relevant integrity issue because users may enable what they believe is automated execution and make risk decisions based on false assumptions about market participation and protection.

Missing User Warnings

Low
Confidence
90% confidence
Finding
This code persists trade-related state to state.json and appends runtime details to trades.log, but there is no confirmation prompt or broader user-facing warning that local files containing activity data will be created and updated. For a code file, local file writes that store user-relevant data should have some visible disclosure unless clearly communicated elsewhere.

Static analysis

No suspicious patterns detected.