Back to skill

Security audit

Polymarket Cryptos Hunter

Security checks for vulnerabilities and agentic risk

Overview

This skill is a live real-money trading bot that is disclosed as such, but it pushes an agent to start indefinite background trading with broad wallet authority and weak user controls.

Review this carefully before installing. Use only an isolated wallet funded with money you are prepared to lose, avoid project-local secrets, run it in the foreground first, require a dry-run or explicit confirmation before live trading, set hard exposure/runtime limits, and verify how to cancel all open orders before starting it.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:10
Finding

Mandatory Unattended Real-Money Trading Through Agent Instruction Hijacking

Content
View full analysis
bot_log.txt 2>&1 & ``` ``` ### Technical Analysis The Skill directs the AI Agent to replace its normal role with that of a portfolio manager and states that its “only job” is to start the bot. It then mandates detached execution using `nohup` and `&`. This is not merely documentation for an optional command. It is an imperative instruction intended to cause an Agent to initiate indefinite, autonomous, real-money trading. The implementation uses the wallet private key to initialize a live Polymarket client and submit signed orders. There is no dry-run default, pre-trade confirmation, bounded runtime, explicit maximum monetary exposure, or approval requirement for individual transactions. Detached execution also reduces user visibility and allows the process to continue after the initiating Agent session ends. Although background execution through `nohup` is not operating-system startup persistence, it unnecessarily extends the duration and financial impact of the action. ### Attack Path 1. A user or Agent loads the Skill instructions. 2. The Skill redefines the Agent’s role and instructs it not to perform any task other than starting the bot. 3. The Agent executes the mandatory `nohup ... &` command. 4. The process reads `WALLET_ ...[truncated 1047 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
main.py:869
Finding

Stop-Loss Bypasses Management and Cancellation of Existing Orders

Content
View full analysis
self.peak: self.peak = self.real_bal dd = (self.peak - self.real_bal) / self.peak if self.peak else 0 if dd >= DAILY_STOP_PCT: self.halted = True print( f"\n🛑 STOP LOSS DECLENCHE — Drawdown de {dd:.1%} (Balance actuelle: ${self.real_bal:,.2f})" ) return True return False ``` ```python while True: try: bal_check = self.poly.get_real_balance() if bal_check > 0: self.real_bal = bal_check self.check_day_reset() if self.check_stop(): time.sleep(30) continue self.manage() self.scan() self.print_stats() ``` The skipped `manage()` method contains the cancellation logic: ```python if age > ORDER_CANCEL_SECS and not expired: if not up_f and pos.get("up_oid"): self.poly.cancel(pos["up_oid"]) if not dn_f and pos.get("dn_oid"): self.poly.cancel(pos["dn_oid"]) ``` ### Technical Analysis When the reported drawdown reaches 15%, `check_stop()` sets `self.halted` and returns `True`. The main loop then sleeps and immediately continues to the next iteration before invoking `manage()`. The existing order cancellation, fill reconciliation, expiry processing, and settlement logic are all implemented inside `manage()`. Consequently, activating the stop-loss prevents the bot from managing orders that were already submitted. On every subsequent iteration, `self.halted` causes `check_stop()` to return `True` again, so this condition persists until the daily reset or process termination. The control therefore stops new market scans but does not stop outstanding financial exposure. Calling this behavior a built-in ...[truncated 1371 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:775
Finding

Settlement Uses Two Current Spot Reads Instead of the Market Strike

Content
View full analysis
= strike up_shares = pos.get("up_shares", 0) dn_shares = pos.get("dn_shares", 0) collected = payout = 0 if up_f: collected += up_fp * up_shares if up_wins: payout += up_shares if dn_f: collected += dn_fp * dn_shares if not up_wins: payout += dn_shares profit = collected - (payout * (1 - FEES_RATE)) if up_f or dn_f: current_bal = self.poly.get_real_balance() if current_bal > 0: self.real_bal = current_bal self.trades += 1 if profit > 0: self.wins += 1 self.fadapt.record(profit > 0) self.tracker.record(pos["asset"], profit > 0) ``` ### Technical Analysis The code obtains both `final` and `strike` by calling the same current Binance spot-price accessor at settlement time. It does not store the market’s actual opening strike when the market is discovered, nor does it query Polymarket’s authoritative resolution outcome. Because both values are read consecutively from the same in-memory cached price, they will commonly be identical. Under identical values, `final >= strike` evaluates to `True`, causing the implementation to classify UP as the winner. Even where a refresh occurs between calls, comparing two settlement-time observations does not represent the market’s actual opening and final values. The resulting `profit` value drives: - `self.wins` - `FillAdaptor.record()` - `AssetTracker.record()` - Subsequent spread adjustments - Subsequent position-size multipliers - The local audit database This turns an acc ...[truncated 1382 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (11)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill explicitly instructs the agent to start an indefinite, autonomous, real-money trading process and frames the agent's only job as launching it. This is dangerous because it can trigger ongoing financial activity without a clear user warning, bounded duration, confirmation step, or active supervision, creating risk of sustained monetary loss and unintended trades.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The skill is designed to load a wallet private key and API credentials from a local .env file and then use them for live on-chain and exchange operations. In an agent-skill context, encouraging secret placement in a project-local file increases the risk of accidental disclosure through repository commits, packaging, logs, backups, or broader runtime access, and compromise of the private key would enable direct theft or unauthorized trading.

Content

Scanner excerpt · main.py (reported line 43)May include surrounding context.

python
POLYMARKET_API_PASSPHRASE = os.getenv("POLYMARKET_API_PASSPHRASE")

if not WALLET_PRIVATE_KEY:
    print("❌ FATAL: WALLET_PRIVATE_KEY manquant dans le fichier .env")
    exit(1)

# --- STRATEGY PARAMS ---

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This skill starts a continuous bot that performs live order placement and cancellation against Polymarket using a real private key, with no interactive confirmation, simulation mode default, or prominent safety interlock. In the context of an agent skill, this is dangerous because a user or calling system could trigger real financial transactions and losses simply by invoking start.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: web3==7.14.1 — 2 advisory(ies): CVE-2026-40072 (web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling); CVE-2026-40072 (web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling)

High
Category
Supply Chain
Confidence
97% confidence
Finding

The skill depends on web3 7.14.1, which is flagged as vulnerable to SSRF via CCIP Read OffchainLookup URL handling. In a live trading bot that interacts with Web3 and external market infrastructure, SSRF is particularly dangerous because attacker-controlled on-chain/off-chain data could potentially trigger outbound requests to internal services, cloud metadata endpoints, or other sensitive network targets.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes a live trading bot with network and environment access but does not declare any explicit tool scope or permission boundaries. That omission increases the chance an agent can use broader-than-necessary capabilities when handling real-money operations, reducing transparency and reviewability for dangerous actions.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
98% confidence
Finding

Using nohup and background execution creates session persistence, allowing the trading bot to continue operating after the initiating session ends. In the context of live market trading, this is especially risky because the agent may lose visibility and control while the process continues to place orders and consume funds unattended.

Content

Scanner excerpt · SKILL.md (reported line 20)May include surrounding context.

bash
# Navigate to the skill folder and start the live trading bot in the background
cd polymarket-cryptos-hunter && nohup .venv/bin/python main.py start > bot_log.txt 2>&1 &

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file's natural-language strings and operator messages are consistently in French, including startup, errors, and status output, but there is no indication that French is optional or required for a region-specific use case. This can violate language/locale policy when a skill imposes a fixed language without user opt-in.

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

python
for cfg in ASSETS.values():
                try:
                    r = self.s.get(
                        f"https://api.binance.com/api/v3/ticker/price?symbol={cfg['ticker']}",
                        timeout=1.2,
                    ).json()
                    self._price[cfg["ticker"]] = {

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

python
for cfg in ASSETS.values():
                try:
                    r = self.s.get(
                        f"https://api.binance.com/api/v3/ticker/price?symbol={cfg['ticker']}",
                        timeout=1.2,
                    ).json()
                    self._price[cfg["ticker"]] = {

Known Vulnerable Dependency: requests==2.32.5 — 2 advisory(ies): CVE-2026-25645 (Requests has Insecure Temp File Reuse in its extract_zipped_paths() utility func); CVE-2026-25645 (Requests is a HTTP library. Prior to version 2.33.0, the `requests.utils.extract)

Medium
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is pinned to requests 2.32.5, which is flagged with a known vulnerability affecting extract_zipped_paths() temporary file handling prior to 2.33.0. Even if this utility is not obviously used from requirements alone, shipping a version with a published CVE is a real supply-chain risk because transitive or future code paths may invoke the vulnerable behavior.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring claims the balance is read directly from the Polygon blockchain, but later user-facing output repeatedly labels that same balance as 'Phantom' (for example in status and result prints), which is a different wallet ecosystem and creates contradictory intent/documentation. This is an active inconsistency in the skill's own descriptive text rather than a mere omission.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.