Back to skill

Security audit

Smart Money Trader

Security checks for vulnerabilities and agentic risk

Overview

The skill is openly a Polymarket trading tool, but live mode can place real-money trades from externally supplied signals with limited validation or confirmation.

Install only if you are comfortable giving this skill a Simmer API key and letting it submit Polymarket trades when --live is used. Prefer dry-run or TRADING_VENUE=sim first, use a low and revocable trading limit, pin dependencies yourself, and avoid overriding SMART_MONEY_API_URL unless you fully trust the endpoint.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T08 · Insecure Dependencies

Warning
Location
clawhub.json:3
Finding
Unpinned Third-Party Dependencies Handle Trading Credentials and Operations<![CDATA[ ## Vulnerability Details **File Location**: `clawhub.json`, lines 3-6 **Vulnerability Type**: Supply-chain exposure through unpinned dependencies **Risk Level**: Medium ### Vulnerable Code ```json "requires": { "pip": ["simmer-sdk", "python-dotenv"], "env": ["SIMMER_API_KEY"] }, ``` ### Technical Analysis The Skill declares `simmer-sdk` and `python-dotenv` without exact versions or package integrity hashes. Consequently, installation may resolve to any version accepted by the package manager at that time. This is particularly security-sensitive for `simmer-sdk`. The Skill imports `SimmerClient` from that dependency and gives it the `SIMMER_API_KEY`: ```python from simmer_sdk import SimmerClient def get_client(): """Initialize Simmer client from environment.""" api_key = os.environ.get("SIMMER_API_KEY") if not api_key: raise RuntimeError("SIMMER_API_KEY not set. Get one at https://simmer.markets/dashboard") venue = os.environ.get("TRADING_VENUE", "polymarket") return SimmerClient(api_key=api_key, venue=venue) ``` The dependency therefore executes inside the Skill's process with access to its environment and authenticated trading operations. The dependency source is not included in the audited project, so its network destinations, credential handling, and order implementation could not be independently verified. Unpinned versions are not proof that the current packages are malicious. They nevertheless create a supply-chain weakness because a compromised publisher account, malicious future release, dependency takeover, or unexpected breaking update could alter the code executed after this Skill has been reviewed. ### Attack Path 1. An attacker compromises the publication process or maintainer account for a declared package, or publishes a malicious version through another package-supply-chain attack. 2. The environment installs dependencies from `clawhub.json` without enforcing a reviewed version or expected pac ...[truncated 963 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every dependency to a specific, reviewed version, for example: ```text simmer-sdk==<reviewed-version> python-dotenv==<reviewed-version> ``` 2. Generate a lockfile containing cryptographic hashes and require hash verification during installation. 3. Install only from an explicitly configured trusted package index. 4. Review the source and transitive dependency tree of `simmer-sdk`, especially its initialization, authentication, telemetry, and trade-submission code. 5. Use a narrowly scoped, revocable API key with the lowest available trading and account permissions. 6. Run the Skill in a sandbox that restricts filesystem access, environment-variable exposure, and outbound network destinations. 7. Add automated dependency provenance, vulnerability, and unexpected-update checks to the release process. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
smartmoney_trader.py:84
Finding
Unauthenticated External Signal Data Can Direct Real-Money Trades<![CDATA[ ## Vulnerability Details **File Location**: `smart_money_signal.py`, lines 45-55; `smartmoney_trader.py`, lines 84-148 **Vulnerability Type**: Insufficient validation of externally supplied financial instructions **Risk Level**: High ### Vulnerable Code The signal client trusts data returned by the configurable external endpoint: ```python url = api_url or DEFAULT_API_URL try: req = Request(url, headers={"User-Agent": "yh-polymarket-smart-money/1.0"}) with urlopen(req, timeout=REQUEST_TIMEOUT) as resp: data = json.loads(resp.read().decode("utf-8")) if data.get("ok") and data.get("signals"): return data["signals"] return [] except (HTTPError, URLError, json.JSONDecodeError, TimeoutError) as e: print(f"⚠️ Smart Money API error: {e}", file=sys.stderr) return [] ``` The returned score and side are normalized without enforcing score bounds, an allowed-side set, signal freshness, or authenticated provenance: ```python score = float(signal.get("score", 0)) price = float(signal.get("price", 0.5)) side = signal.get("side", "YES").upper() # Convert 0-10 score to 0-1 confidence confidence = score / 10.0 # Derive implied probability from side and price if side == "YES": implied_prob = price else: implied_prob = 1.0 - price ``` The external slug selects the market to import: ```python matched = [] for sig in signals: slug = sig.get("smart_money_slug", "") if not slug: continue url = f"https://polymarket.com/event/{slug}" try: result = client.import_market(url) market_id = result.get("market_id") question = result.get("question", sig.get("smart_money_market", "")) if market_id: matched.append((sig, market_id, question)) print(f" ✅ {question[:60]}") else: status = result.get("status", "unknown") print(f" ⚠️ {slug}: {status}") except Exception as e: print(f" ❌ Import faile ...[truncated 4501 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require signed signals and verify them against a pinned, trusted public key before processing. 2. Define and enforce a strict response schema: - `score` must be numeric and within `0` to `10`. - `side` must be exactly `YES` or `NO`. - `price` must be within the valid market range. - Slugs and identifiers must match conservative allowlisted formats. - Timestamps must parse correctly and fall within a short accepted age. 3. Add a unique signal identifier and persist processed identifiers to prevent replay and duplicate trades. 4. Query current positions before trading and reject duplicate or excessive exposure to the same market or outcome. 5. Add run-level and account-level controls, including: - Maximum total spend per run. - Maximum number of orders. - Daily loss and exposure limits. - Per-market exposure limits. 6. Require explicit per-order confirmation for real-money trades, or require independent corroboration from a second trusted source. 7. Restrict or remove `SMART_MONEY_API_URL` in production. If configurability is required, enforce an allowlist of HTTPS hosts and pin the expected service identity where feasible. 8. Verify that the imported market's question, condition identifier, token identifiers, and outcome mapping match the signed signal before submitting an order. 9. Treat malformed or unknown values as rejection conditions rather than applying defaults. 10. Implement and locally enforce the documented circuit breaker instead of relying solely on behavior inside the unaudited SDK. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (7)

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

Critical
Category
Data Flow
Content
url = api_url or DEFAULT_API_URL
    try:
        req = Request(url, headers={"User-Agent": "yh-polymarket-smart-money/1.0"})
        with urlopen(req, timeout=REQUEST_TIMEOUT) as resp:
            data = json.loads(resp.read().decode("utf-8"))
            if data.get("ok") and data.get("signals"):
                return data["signals"]
Confidence
93% confidence
Finding
The code allows the outbound API destination to be overridden by the SMART_MONEY_API_URL environment variable and then performs a network request to that URL without validation. In environments where attackers or untrusted integrations can influence environment variables, this creates an SSRF-style primitive that can redirect requests to internal services, cloud metadata endpoints, or attacker-controlled hosts, and the fetched response is then trusted as signal data.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill advertises live trading and copy-trading behavior that the analyzed content does not substantiate, creating a dangerous mismatch between user expectations and actual implemented behavior. In trading contexts, this can mislead operators into believing orders, safeguards, or execution logic exist when they may not, increasing the risk of unsafe automation, bad financial decisions, or later swapping in hidden behavior under a trusted description.

Credential Access

High
Category
Privilege Escalation
Content
python smartmoney_trader.py --status    # Show current positions and signal status

Requires:
    SIMMER_API_KEY environment variable (from .env or shell)
"""

import os
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
python smartmoney_trader.py --status    # Show current positions and signal status

Requires:
    SIMMER_API_KEY environment variable (from .env or shell)
"""

import os
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# Load .env from project root
try:
    from dotenv import load_dotenv
    _env_path = Path(__file__).resolve().parent / ".env"
    if _env_path.exists():
        load_dotenv(_env_path)
except ImportError:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares capabilities that require environment access and outbound network use, but it does not explicitly restrict or disclose tool scope via permissions or allowed-tools. In an agent environment, missing scope declarations can cause over-broad execution privileges, making unintended secret access or external calls more likely if the skill is invoked or later extended.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill explicitly documents a --live mode for Polymarket trading but does not present a clear warning that this can execute real-money trades. In a financial skill, lack of prominent user-facing risk disclosure increases the chance of accidental real-fund execution, especially when paired with concise quick-start commands that normalize enabling live mode.

Static analysis

No suspicious patterns detected.