Back to skill

Security audit

simmer-mcp-setup

Security checks for vulnerabilities and agentic risk

Overview

The skill is transparent about setting up a trading MCP server, but it needs review because it runs an unpinned npm package with a live API key and stores that key in plaintext for several runtimes.

Install only if you are comfortable granting Simmer MCP access to a Simmer API key and trading-capable tools. Prefer a pinned, reviewed simmer-mcp version, use environment-variable forwarding or a secret store instead of plaintext config where the runtime supports it, avoid project configs that might be committed, and use a separate low-risk or unclaimed agent/key on shared or cloud-hosted runtimes.

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

Error
Location
SKILL.md:98
Finding
Unpinned npm Package Is Automatically Retrieved and Executed<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 98–103 **Vulnerability Type**: Unpinned third-party dependency execution **Risk Level**: High ### Vulnerable Code ```bash npm install -g simmer-mcp ``` ```text This step is **optional**. The MCP config in Step 4 uses `npx -y simmer-mcp`, which fetches the package on first launch even without a global install. Installing globally just makes the first launch slightly faster (no fetch delay). If you skip Step 3, everything still works. If you do install it and get an EACCES permission error on Linux/macOS: do NOT `sudo npm install` (creates permission tangles later). Either fix npm's global directory permissions per npm's docs, or just skip the global install — the `npx -y simmer-mcp` form in the config works either way. ``` The unpinned invocation is subsequently embedded in runtime configurations throughout the document: ```json { "command": "npx", "args": ["-y", "simmer-mcp"], "env": { "SIMMER_API_KEY": "sk_live_..." } } ``` ### Technical Analysis The Skill repeatedly configures agent runtimes to execute `npx -y simmer-mcp` without specifying an exact package version or integrity hash. `npx` may download the package from the npm registry on first launch, while `-y` suppresses the normal installation confirmation. Consequently, the code executed by the runtime is not fixed to the code reviewed when this Skill was published. A compromised npm publisher account, malicious package release, registry compromise, or future compromised update could replace the effective payload. npm installation lifecycle scripts may also execute during retrieval. This risk is amplified because the package is launched with `SIMMER_API_KEY` in its environment and is intentionally granted market and trading capabilities. A malicious package would therefore receive the API key directly and would execute with the operating-system privileges of the agent runtime. The global installation alternative ...[truncated 1756 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the dependency to an exact reviewed version, for example: ```bash npx --yes simmer-mcp@3.5.2 ``` Apply the same exact version to every JSON, YAML, TOML, and CLI example. 2. Prefer installing from a lockfile-controlled local project rather than resolving a package dynamically whenever the runtime starts. 3. Verify package integrity against a trusted digest or signed provenance before execution. Document the expected package owner, version, and checksum. 4. Disable or strictly control npm lifecycle scripts during installation where compatible with the package: ```bash npm install --ignore-scripts --save-exact simmer-mcp@3.5.2 ``` 5. Do not use `npx -y` as a persistent runtime command. Resolve and verify the package during an explicit installation phase, then execute a fixed local binary. 6. Run the MCP server in a restricted environment with only the required environment variables, filesystem access, and network destinations. Do not expose unrelated user or agent credentials. 7. Establish a deliberate update process that reviews and tests new versions before changing the pinned version. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:193
Finding
API Key Is Persisted in Plaintext Agent Configuration<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 193–205 **Vulnerability Type**: Plaintext sensitive credential storage **Risk Level**: High ### Vulnerable Code ```text This writes `~/.claude.json` for you with the correct `command`/`args`/`env` structure. The `"$SIMMER_API_KEY"` expansion bakes the literal key value into the config (MCP runtimes don't expand shell vars at server-launch time). **Fallback (if `claude mcp add` isn't available in this Claude Code version):** add the following to `~/.claude.json` under `mcpServers` (create the key if it doesn't exist) — use the literal API key value, not `$VAR`: ``` ```json { "mcpServers": { "simmer": { "command": "npx", "args": ["-y", "simmer-mcp"], "env": { "SIMMER_API_KEY": "sk_live_..." } } } } ``` Comparable literal-secret examples are also provided for Cursor at lines 214–223, Hermes at lines 363–370, and unknown runtimes at lines 518–526. The document further acknowledges at lines 559–560 that `claude mcp get simmer` prints the key in cleartext. ### Technical Analysis The instructions deliberately expand and persist `SIMMER_API_KEY` as a literal value in user-level MCP configuration. This changes the key from an ephemeral process secret into a long-lived plaintext credential. Any process running as the same user, malware with user-level file access, backup or synchronization software, diagnostic collection, or an accidentally shared configuration file may obtain the key. Project-scoped examples create an additional risk that a configuration containing the credential could be committed to source control. The access is related to the declared setup functionality because the MCP subprocess requires authentication. However, literal storage is not consistently the minimum privilege necessary. The same document demonstrates safer environment forwarding for Codex and environment references for OpenClaw. Where a runtime cannot forward variabl ...[truncated 2002 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer environment-variable forwarding by name instead of embedding the value. Use runtime-native mechanisms equivalent to Codex's `env_vars = ["SIMMER_API_KEY"]`. 2. Where supported, use a structured secret reference or operating-system credential store rather than a literal configuration value. 3. If a runtime requires a wrapper, launch the MCP server through a minimal script that retrieves the key from a protected secret store and injects it only into the child process environment. 4. If plaintext storage is unavoidable: - Obtain explicit user approval. - Use user-only file permissions such as `0600`. - Keep the file outside project directories and synchronization roots. - Warn users never to commit it to source control. - Document key rotation and revocation procedures. 5. Remove literal-key examples from project-scoped configuration instructions. Add placeholder validation that refuses real-looking `sk_live_` values in repository files. 6. Avoid commands known to reveal environment values. Replace `claude mcp get simmer` troubleshooting guidance with secret-safe status checks, or explicitly instruct users not to record, paste, or share its output. 7. Scope API credentials to the minimum possible permissions, venue, account, and transaction limits. If the service does not currently support scoped keys, add that capability and recommend dedicated setup-only or paper-trading credentials. 8. Rotate the key immediately if a configuration file, command output, transcript, backup, or repository containing it has been exposed. ]]>
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (29)

External Script Fetching

High
Category
Supply Chain
Content
**Case C — no agent registered yet.** Register one now:
```bash
curl -X POST https://api.simmer.markets/api/sdk/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "description": "What this agent does"}'
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Chaining Abuse

High
Category
Tool Misuse
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Agent Config Directory Access

High
Category
Agent Snooping
Content
Codex (the OpenAI CLI, `codex-cli`) reads **TOML**, not JSON, and ships its own MCP CLI —
do not paste the JSON block from the other runtimes into it. Its config file is
`~/.codex/config.toml`, or `$CODEX_HOME/config.toml` when that variable is set (the ChatGPT
desktop app sets it); every path below means whichever one your Codex reads.

**Write this block** under `mcp_servers` in that file. It is the whole entry; there is
Confidence
90% confidence
Finding
The skill instructs modifying a sensitive agent configuration file in the user's home directory to persistently register a third-party MCP server. Persistent config modification expands the trust boundary and can grant the server automatic startup, access to forwarded secrets, and influence over future agent sessions beyond the immediate task.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
**Tools listed but API calls return 401.**
- `SIMMER_API_KEY` env didn't make it into the MCP subprocess. The env block in the config has to be a direct value, not a `$VAR` reference — most MCP clients don't expand shell vars at server-launch time.
- Verify the key value: `printenv SIMMER_API_KEY | cut -c1-20` — must start with `sk_live_`. A common silent failure: install commands that use `pbpaste` or clipboard-read primitives can write the *install command text itself* as the key value when the user copies the command after copying the key. Fix: get a fresh key from [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill), then `export SIMMER_API_KEY="sk_live_..."` typed/pasted directly.

**`npm install -g simmer-mcp` fails with EACCES on Linux/macOS.**
- Don't `sudo npm install` — that creates permission problems later. Either fix npm's global directory permissions per [npm's docs](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally), or just use the `npx -y simmer-mcp` form in your config (no global install needed; npx fetches on first launch).
Confidence
70% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

External Script Fetching

High
Category
Supply Chain
Content
## Anti-patterns

- **Don't auto-install Node.js via `curl | sh`** — modifying the user's system without explicit approval is bad practice. Show the platform-specific install hint and let the user decide.
- **Don't paste the API key from clipboard into a pipe.** Use `read -s` (per [SIM-2118](https://github.com/SpartanLabsXyz/simmer/issues/2118)).
- **Don't `sudo npm install -g`.** Fix the underlying npm permissions, or use `npx -y simmer-mcp` in the config (no global install needed).
- **Don't tell the user "it should work now" without verifying.** Run Step 6 — confirm a real tool call returns real data.
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Rp1

Medium
Category
MCP Rug Pull
Confidence
98% confidence
Finding
The skill repeatedly instructs runtimes to launch `simmer-mcp` via `npx -y simmer-mcp` without pinning a specific version or integrity hash. That causes each install/bootstrap to trust the latest package from the registry at execution time, creating a software supply-chain risk where a compromised or malicious package update could gain code execution inside the agent's MCP context and access configured secrets.

External Transmission

Medium
Category
Data Exfiltration
Content
**Case C — no agent registered yet.** Register one now:
```bash
curl -X POST https://api.simmer.markets/api/sdk/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "description": "What this agent does"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
**Case C — no agent registered yet.** Register one now:
```bash
curl -X POST https://api.simmer.markets/api/sdk/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "description": "What this agent does"}'
```
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
|---|---|
| macOS | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. Or `brew install node` if Homebrew is installed. |
| Windows | Download installer from [nodejs.org](https://nodejs.org) (LTS) and double-click. |
| Linux (Debian/Ubuntu) | `sudo apt update && sudo apt install nodejs npm` |
| Linux (Fedora/RHEL) | `sudo dnf install nodejs npm` |

The Node.js installer bundles npm, so installing Node.js gives you both. After install, the user needs to reopen their terminal so `node`/`npm` land on PATH, then re-run this step.
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Rp1

Medium
Category
MCP Rug Pull
Confidence
98% confidence
Finding
Using unpinned `npx -y simmer-mcp` for first launch means the code fetched and executed is whatever the registry serves at that moment. Because this MCP process receives API keys and may expose trading actions, a malicious upstream update could execute arbitrary code and misuse those credentials.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The fallback guidance to use `bunx` in place of `npx` retains the same problem: it executes an unpinned package from a remote registry. Even though this is phrased as troubleshooting, it still directs users to fetch code at runtime without version control or integrity guarantees.

Rp1

Medium
Category
MCP Rug Pull
Confidence
98% confidence
Finding
The Claude Code command adds an MCP server that will always execute `npx -y simmer-mcp` on startup without pinning. Since the same command also embeds `SIMMER_API_KEY` into the server environment, a compromised upstream package could immediately exfiltrate credentials or perform unintended actions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The fallback JSON for Claude Code config launches `npx -y simmer-mcp` without version pinning, turning every MCP startup into a trust-on-first-use fetch. In this context, the MCP server is granted access to a live trading API key, which materially increases the impact of a supply-chain compromise.

Session Persistence

Medium
Category
Rogue Agent
Content
This writes `~/.claude.json` for you with the correct `command`/`args`/`env` structure. The `"$SIMMER_API_KEY"` expansion bakes the literal key value into the config (MCP runtimes don't expand shell vars at server-launch time).

**Fallback (if `claude mcp add` isn't available in this Claude Code version):** add the following to `~/.claude.json` under `mcpServers` (create the key if it doesn't exist) — use the literal API key value, not `$VAR`:
```json
{
  "mcpServers": {
Confidence
96% confidence
Finding
The Claude fallback instructs users to place the literal `SIMMER_API_KEY` value directly into persistent config (`~/.claude.json`). Storing a live trading credential in plaintext in a long-lived agent config materially increases exposure to local compromise, accidental disclosure in backups/transcripts, and unintended reuse by future sessions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The OpenClaw CLI example installs an MCP server backed by unpinned `npx` arguments, so runtime package resolution remains uncontrolled. Because this server can expose portfolio, market, and trading functions, compromise of the package source can lead to arbitrary code execution and sensitive credential misuse.

Session Persistence

Medium
Category
Rogue Agent
Content
`~/.codex/config.toml`, or `$CODEX_HOME/config.toml` when that variable is set (the ChatGPT
desktop app sets it); every path below means whichever one your Codex reads.

**Write this block** under `mcp_servers` in that file. It is the whole entry; there is
nothing else to add for Simmer:

```toml
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Static analysis

No suspicious patterns detected.