Mcp subprocess env filtering
Skill kjuhwa/skills-hub/skills/security/mcp-subprocess-env-filtering
When spawning a stdio MCP server (or any untrusted subprocess), allowlist/denylist environment variables so app-level auth tokens and third-party API keys don't leak into the child process.From its SKILL.md
npx -y skills add kjuhwa/skills-hub --skill mcp-subprocess-env-filteringAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
2.7 KB, 540 tokens by cl100k_base, as published. Nobody here has run it
Filter env vars to MCP subprocesses
When to use
- Spawning a stdio MCP server / any third-party subprocess.
- Host process holds credentials the subprocess does not need (ANTHROPIC_API_KEY, GITHUB_TOKEN, AWS_*).
- Users add arbitrary MCP servers - you can't audit every
npx some-random-mcp.
How it works
- Maintain a
BLOCKED_ENV_VARSdenylist of well-known secret names:- App auth:
ANTHROPIC_API_KEY,CLAUDE_CODE_OAUTH_TOKEN - Cloud:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN - Common tokens:
GITHUB_TOKEN,GH_TOKEN,OPENAI_API_KEY,GOOGLE_API_KEY,STRIPE_SECRET_KEY,NPM_TOKEN.
- App auth:
- When building the subprocess env, start from
process.env, drop every key in the denylist. - Allow the MCP source config to explicitly opt back in via a per-server
env: { FOO: '...' }field — the source owner has to know what they're passing. - Mirror the list in any secondary spawn site (e.g.
session-tools-core'stransform_data) - the repo calls this out in a comment so the two lists don't drift.
Example
const BLOCKED_ENV_VARS = [
'ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN',
'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_SESSION_TOKEN',
'GITHUB_TOKEN', 'GH_TOKEN', 'OPENAI_API_KEY', 'GOOGLE_API_KEY',
'STRIPE_SECRET_KEY', 'NPM_TOKEN',
];
const childEnv = { ...process.env, ...sourceConfig.env };
for (const k of BLOCKED_ENV_VARS) delete childEnv[k];
spawn(cmd, args, { env: childEnv });
Gotchas
- A denylist is inherently incomplete - prefer an allowlist for truly untrusted processes.
- Don't forget to scrub from the user's shell env (
.zshrcexports) too - loading their shell env into your app first (seeshell-env.tsin craft-agents) can pull in MORE secrets. - Document the list in one canonical place and reference it from every spawn site; drift is the #1 failure mode.
- The README of the project lists these publicly - treating the list as "security through documentation" is fine because the real control is the code filter, not the secret of the list.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.