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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · manual_trade.py (reported line 50)May include surrounding context.

python
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

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · manual_trade.py (reported line 61)May include surrounding context.

python
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

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · manual_trade.py (reported line 96)May include surrounding context.

python
method="POST",
    )
    try:
        resp = urllib.request.urlopen(req, timeout=30)
        data = json.loads(resp.read())
        markets = data.get("markets", [])
        if not markets:

Credential Access

High
Category
Privilege Escalation
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.

Content

Scanner excerpt · manual_trade.py (reported line 22)May include surrounding context.

python
try:
    from dotenv import load_dotenv
    load_dotenv("/root/.openclaw/.env")
except Exception:
    pass

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
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.

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

python
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",

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.