Skip to content

server-everything: get-env tool returns full process.env without any filtering #3986

@DrDexter6000

Description

@DrDexter6000

I was doing a security audit of the official MCP servers and stumbled into something that gave me pause.

The get-env tool in server-everything returns the entire process.env object -- unfiltered, unsanitized, with no parameter required. Call it with empty args and you get ~6KB of every environment variable on the host machine.

What I saw

The tool's handler is literally:

server.registerTool(name, config, async (args): Promise<CallToolResult> => {
  return {
    content: [{ type: "text", text: JSON.stringify(process.env, null, 2) }],
  };
});

inputSchema is {}, so zero arguments triggers it. No annotations, no filtering, no opt-in.

What this leaks

On a typical Windows dev box this dumps:

  • USERNAME, USERDOMAIN, COMPUTERNAME -- host and user identity
  • PATH, APPDATA, LOCALAPPDATA -- full directory structure
  • HOMEPATH, USERPROFILE -- home directory path
  • Any API keys the user happens to have in env: OPENAI_API_KEY, ANTHROPIC_API_KEY, GITHUB_TOKEN, etc.

The "etc" is the problem. You can't know what's in someone's env.

Why this matters for an official example

server-everything is the demo server. People copy it to learn the protocol. If get-env stays as-is, that pattern propagates. I've already seen community servers that copied the "return raw env" pattern because "the official one does it."

Also: the tool has no annotations object, so an MCP client has zero signal that this is a high-sensitivity read operation.

Suggested fixes

Option 1 (safest): Require a specific key parameter.

inputSchema: {
  type: 'object',
  properties: {
    key: { type: 'string', description: 'Specific environment variable name' }
  },
  required: ['key']
}

Option 2 (if you want to keep the bulk dump): Filter known-sensitive patterns.

const SENSITIVE = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIAL|AUTH/i;
const filtered = Object.fromEntries(
  Object.entries(process.env).filter(([k]) => !SENSITIVE.test(k))
);

Option 3 (annotation-only, weakest but still useful): Add readOnlyHint: true and a big warning in the description that this returns the full environment.

My vote is Option 1. "Get one env var by name" is still a useful demo of a tool that reads from the host, without being a foot-gun.


Happy to open a PR if the maintainers agree on a direction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions