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.
I was doing a security audit of the official MCP servers and stumbled into something that gave me pause.
The
get-envtool inserver-everythingreturns the entireprocess.envobject -- 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:
inputSchemais{}, 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 identityPATH,APPDATA,LOCALAPPDATA-- full directory structureHOMEPATH,USERPROFILE-- home directory pathOPENAI_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-everythingis the demo server. People copy it to learn the protocol. Ifget-envstays 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
annotationsobject, 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.
Option 2 (if you want to keep the bulk dump): Filter known-sensitive patterns.
Option 3 (annotation-only, weakest but still useful): Add
readOnlyHint: trueand 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.