Back to skill

Security audit

Manual Trade Placement

Security checks for vulnerabilities and agentic risk

Overview

This skill is openly designed for live Polymarket trading, but it can place or cancel real orders using private-key credentials without enough confirmation, validation, or credential scoping safeguards.

Review carefully before installing. Use only a dedicated low-balance wallet and scoped Simmer key, avoid storing unrelated secrets in /root/.openclaw/.env, pin and review the SDK version, provide explicit prices and conservative amounts, and do not rely on --dry-run for cancellation because the current code cancels before honoring it.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
manual_trade.py:18
Finding
Global Agent Secret File Is Loaded Beyond the Skill's Minimum Requirements## Vulnerability Details **File Location**: `manual_trade.py:18-21` **Vulnerability Type**: Excessive credential access and violation of least privilege **Risk Level**: Medium ### Vulnerable Code ```python try: from dotenv import load_dotenv load_dotenv("/root/.openclaw/.env") except Exception: pass ``` ### Technical Analysis The Skill unconditionally attempts to load `/root/.openclaw/.env`, a global Agent environment file. Loading this file imports all variables it contains into the current process environment, even though the declared functionality only requires `SIMMER_API_KEY` and `WALLET_PRIVATE_KEY`. This crosses a least-privilege boundary: unrelated credentials stored in the Agent's global environment become available to the Skill process and all imported Python packages. In particular, `simmer_sdk` executes in the same process and can access every loaded environment variable through `os.environ`. The broad exception handler also suppresses configuration and permission errors, making this access less visible to operators. ### Attack Path 1. An operator stores multiple service credentials in `/root/.openclaw/.env`. 2. The operator invokes `manual_trade.py`. 3. The Skill loads every variable from the global file into its process environment. 4. The imported `simmer_sdk`, a compromised dependency, or future code added to the process reads unrelated secrets from `os.environ`. 5. Those secrets can then be used within the privileges of the affected external accounts or potentially transmitted by dependency-controlled code. No direct exfiltration of unrelated environment variables is implemented in the reviewed project. Exploitation therefore requires malicious or compromised code executing in the same process. ### Impact Assessment The immediate scope includes every credential present in `/root/.openclaw/.env`, rather than only the two credentials declared by the Skill. Depending on the file ...[truncated 423 chars]
Remediation
## Remediation Suggestions - Remove automatic loading of `/root/.openclaw/.env`. - Require the execution environment to supply only the credentials needed by this Skill. - If dotenv support is necessary, use a Skill-specific file with restrictive permissions and an explicit allowlist: ```python from dotenv import dotenv_values values = dotenv_values("/path/to/polymarket-manual-trade.env") for name in ("SIMMER_API_KEY", "WALLET_PRIVATE_KEY"): if name in values: os.environ[name] = values[name] ``` - Validate required variables and fail with a clear error without printing their values. - Run the Skill under a dedicated, unprivileged account rather than relying on a root-owned global configuration. - Minimize the lifetime and scope of wallet credentials, and prefer a restricted signing mechanism if supported.

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding
Security-Critical Trading SDK Dependency Is Not Pinned## Vulnerability Details **File Location**: `clawhub.json:3-6`; supporting references in `SKILL.md:68-72`, `README.md:62-67`, and `manual_trade.py:23` **Vulnerability Type**: Mutable third-party dependency used with financial credentials **Risk Level**: Medium ### Vulnerable Code ```json { "requires": { "env": ["SIMMER_API_KEY", "WALLET_PRIVATE_KEY"], "pip": ["simmer-sdk"] } } ``` The dependency is imported directly into the credential-bearing process: ```python from simmer_sdk import SimmerClient ``` The documentation provides only a lower bound rather than a reproducible version: ```text simmer-sdk >= 0.8.32 ``` ### Technical Analysis Installation metadata requests `simmer-sdk` without an exact version, lockfile, or package hash. Consequently, the code installed during one deployment may differ from the code installed during a later deployment even when the Skill package itself has not changed. This dependency is security-critical: it receives the Simmer API key, performs trade and cancellation requests, and runs in a process that may contain a wallet private key and other credentials loaded from the global Agent environment. There is no evidence that `simmer-sdk` is currently malicious or that dependency confusion has occurred. The vulnerability is the absence of reproducible, integrity-verified dependency resolution for code operating with financial authority. ### Attack Path 1. An attacker compromises the upstream package, maintainer account, distribution channel, or a future package release. 2. A user installs or reinstalls this Skill. 3. The package manager resolves the unpinned `simmer-sdk` requirement to the attacker-controlled or unexpectedly changed release. 4. `manual_trade.py` imports the package and executes its top-level and client code. 5. The compromised package reads process credentials, modifies order parameters, submits unauthorized transactions, or exfiltr ...[truncated 602 chars]
Remediation
## Remediation Suggestions - Pin the SDK to an audited exact version in installation metadata, for example: ```json "pip": ["simmer-sdk==0.8.32"] ``` - Use a lockfile or requirements file containing cryptographic hashes. - Ensure metadata and documentation specify the same exact version. - Install from the official package index through a trusted, authenticated configuration. - Review SDK release changes before upgrading. - Run dependency vulnerability and provenance checks in CI. - Isolate signing material from the SDK where feasible, using a narrowly scoped signer or transaction-approval boundary.

T09 · Insecure Skill Coding Practices

Error
Location
manual_trade.py:181
Finding
Trade Execution Fails Open With a Fabricated Price and Insufficient Numeric Validation## Vulnerability Details **File Location**: `manual_trade.py:181-190` and `manual_trade.py:220-230` **Vulnerability Type**: Unsafe financial transaction handling **Risk Level**: High ### Vulnerable Code ```python limit_price = args.price book = get_best_ask(trade_token) if trade_token else None if limit_price is None: if book and book.get("best_ask"): limit_price = round(min(book["best_ask"] + 0.01, 0.97), 4) print(f" 📊 Book: ask={book['best_ask']} bid={book['best_bid']} → auto-price={limit_price}") else: limit_price = 0.55 print(f" ⚠️ No book data — using fallback price: {limit_price}") ``` The generated or user-supplied values are then used in a real trade: ```python client = get_client(venue=args.venue) result = client.trade( market_id = market_id, side = side.lower(), amount = args.amount, price = limit_price, order_type = args.order, source = TRADE_SOURCE, skill_slug = SKILL_SLUG, allow_rebuy= True, reasoning = f"Manual trade: {side} ${args.amount:.2f} @ {limit_price} ({args.order})", ) ``` ### Technical Analysis When price discovery fails because the token is missing, the CLOB endpoint is unavailable, the response is malformed, or any exception occurs in `get_best_ask`, the program continues with a hardcoded price of `0.55`. This value is not derived from the selected market and may differ substantially from the current price or the user's intent. The implementation therefore fails open for a security-sensitive financial operation. It treats the absence of trustworthy market data as permission to construct and submit a real order. The CLI accepts `float` values for amount and price but performs no local checks that: - The amount is finite and greater than zero. - The price is finite and within the valid prediction-market range. - The amount is below an operator-defined trans ...[truncated 1893 chars]
Remediation
## Remediation Suggestions - Fail closed when live price discovery is unavailable: ```python if limit_price is None: if not book or book.get("best_ask") is None: raise RuntimeError( "Price discovery failed; provide --price explicitly or retry later" ) limit_price = round(min(book["best_ask"] + 0.01, 0.97), 4) ``` - Never substitute a fabricated market price for a real-money operation. - Validate all financial inputs before resolving or submitting an order: ```python import math if not math.isfinite(args.amount) or args.amount <= 0: parser.error("--amount must be a finite positive number") if args.price is not None: if not math.isfinite(args.price) or not 0 < args.price < 1: parser.error("--price must be finite and between 0 and 1") ``` - Add a configurable maximum transaction amount and require explicit confirmation above a conservative threshold. - For automatically calculated prices, enforce a maximum slippage limit relative to a recent trusted quote. - Require explicit confirmation when the computed price differs materially from the displayed market probability. - Consider making `allow_rebuy` opt-in rather than unconditional. - Record and surface the exact validated order parameters before signing or submission. - Add tests covering CLOB outages, missing tokens, malformed books, `nan`, `inf`, negative values, out-of-range prices, and excessive amounts.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (19)

Tainted flow: 'req' from os.environ.get (line 89, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
url = f"https://api.simmer.markets{path}"
    req = urllib.request.Request(url, headers={"Authorization": f"Bearer {API_KEY}", "User-Agent": "Mozilla/5.0"})
    try:
        resp = urllib.request.urlopen(req, timeout=15)
        return json.loads(resp.read())
    except Exception:
        return None
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.environ.get (line 89, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
try:
        url = f"https://clob.polymarket.com/book?token_id={token_id}"
        req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
        book = json.loads(urllib.request.urlopen(req, timeout=10).read())
        asks = book.get("asks", [])
        bids = book.get("bids", [])
        # Sort to ensure correct best prices regardless of API sort order
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.environ.get (line 89, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=30)
        data = json.loads(resp.read())
        markets = data.get("markets", [])
        if not markets:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Credential Access

High
Category
Privilege Escalation
Content
try:
    from dotenv import load_dotenv
    load_dotenv("/root/.openclaw/.env")
except Exception:
    pass
Confidence
76% confidence
Finding
The skill unconditionally attempts to load secrets from /root/.openclaw/.env, which couples it to a privileged filesystem location and may pull in credentials beyond those minimally needed. In a shared or agent-executed environment, implicitly harvesting secrets from a root-owned global file expands secret exposure and can cause unintended credential use across skills.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README promotes live trade execution and market interaction without a prominent warning that commands can trigger real financial transactions and potentially irreversible losses. In an agent context, ambiguous user prompts or misunderstanding of live-vs-preview behavior can lead to unintended trades, making this more dangerous than ordinary documentation gaps.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
Documenting cancellation capability without clearly warning that it can remove or alter existing open orders increases the risk of destructive user mistakes. In a trading agent, a user may issue a vague cancellation command and unknowingly disrupt strategy, lose queue priority, or cancel protective orders, which makes the omission security-relevant in context.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documents capabilities that inherently require network access and reading sensitive environment variables (API keys and private keys), but it does not declare any explicit tool scope or permissions boundary. In an agent setting, this creates a transparency and authorization gap: the agent or reviewer cannot easily tell that the skill can access secrets and perform live external actions, increasing the chance of unintended trade execution or secret misuse.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill enables real-money trading and uses a wallet private key for signing, but the description does not prominently warn that execution can immediately commit funds. In an AI-agent context, insufficient warning materially increases the risk of accidental or socially engineered trade execution, especially when natural-language prompts are enough to trigger orders.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The manifest frames the skill as manual trade placement, but the documented interface also allows canceling open orders. This is a security-relevant capability expansion because cancel actions can materially affect positions, liquidity strategy, and funds availability, yet a caller relying on the top-level description may not realize the skill can perform destructive account actions.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documented cancellation flags allow destructive account actions, but there is no warning that canceling orders may be irreversible in practice and can disrupt trading strategy or market exposure. In an agent-driven workflow, omission of such warnings increases the chance that a vague or mistaken instruction causes unintended order removal.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The manifest exposes a manually invoked trading skill that requires both an API key and a wallet private key, but it defines no trigger scope, confirmation requirement, or invocation constraints. In a financial-trading context, weak invocation boundaries materially increase the chance of unintended or unauthorized order placement, which could directly spend funds or move assets.

External Transmission

Medium
Category
Data Exfiltration
Content
API_KEY = os.environ.get("SIMMER_API_KEY", "")
    payload = json.dumps({"polymarket_url": polymarket_url}).encode()
    req = urllib.request.Request(
        "https://api.simmer.markets/api/sdk/markets/import",
        data=payload,
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        method="POST",
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill exposes destructive order-cancellation behavior that is not disclosed in the manifest, so a caller expecting only trade placement may unknowingly grant broader execution authority than intended. In an agent setting, hidden capabilities are dangerous because they can be invoked through prompt confusion or automation paths that assume the documented scope is complete.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The implementation supports FOK orders and a non-manifest 'sim' venue even though the description says Polymarket manual trades with FAK and GTC. That mismatch increases the effective permission and behavioral surface beyond what users and orchestrators would expect, which is especially risky for financial actions where venue and order type materially change execution outcomes.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The cancel path can remove all open orders on a market immediately with no confirmation, preview, or secondary approval. In a trading skill, that is a meaningful destructive action that can disrupt strategy, lose queue priority, and cause financial harm if triggered accidentally or by a compromised agent workflow.

Description-Behavior Mismatch

Low
Confidence
5% confidence
Finding
The README consistently describes resolving markets, discovering prices, placing FAK/GTC/FOK orders, and optionally cancelling open orders on a market. Those are all directly related to a manual trade placement skill, so there is no clear description-behavior mismatch in this file alone.

Intent-Code Divergence

Low
Confidence
8% confidence
Finding
The README documents additional cancellation flags beyond simple trade placement, but this does not actively contradict the skill's stated purpose because order cancellation is a normal extension of manual trade management. The provided file is documentation only and does not show code behavior that diverges from comments or manifest intent.

Description-Behavior Mismatch

Low
Confidence
88% confidence
Finding
The description repeatedly states that the skill supports FAK and GTC order types and emphasizes those as the tested, working modes. The arguments section expands this to include `FOK`, which is a behavior claim outside the stated manifest scope and may misrepresent the actual intended capability.

Natural-Language Policy Violations

Low
Confidence
71% confidence
Finding
The manifest sets a default venue of "polymarket" and limits venue choices to "polymarket" or "sim" without any natural-language explanation, opt-in, or justification. This can be a policy concern if the skill effectively forces a platform or locale-specific context without documenting user choice.

Static analysis

No suspicious patterns detected.