{"record":{"id":"870023ea28c9864a","repo":"bytedance/deer-flow","slug":"mcp-server-name-sets-environment-variable-en","errorCode":null,"errorMessage":"MCP server '{name}' sets environment variable '{env_name}', which would run arbitrary code at process startup.","messagePattern":"MCP server '(.+?)' sets environment variable '(.+?)', which would run arbitrary code at process startup\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/app/gateway/routers/mcp.py","lineNumber":622,"sourceCode":"\n        command_name = _stdio_command_name(server.command, server_name=name)\n        if command_name not in allowed_commands:\n            allowed = \", \".join(sorted(allowed_commands)) or \"<none>\"\n            raise HTTPException(\n                status_code=status.HTTP_400_BAD_REQUEST,\n                detail=(f\"MCP server '{name}' uses disallowed stdio command '{command_name}'. Allowed commands: {allowed}. Configure {_MCP_STDIO_COMMAND_ALLOWLIST_ENV} to extend this list.\"),\n            )\n\n        exec_flag = _arbitrary_exec_arg(server.args, command=command_name)\n        if exec_flag is not None:\n            raise HTTPException(\n                status_code=status.HTTP_400_BAD_REQUEST,\n                detail=(f\"MCP server '{name}' passes '{exec_flag}' to '{command_name}', which would run arbitrary code. Point the server at a package or module instead.\"),\n            )\n\n        for env_name in server.env:\n            if env_name.strip().upper() in _CODE_INJECTING_ENV_VARS:\n                raise HTTPException(\n                    status_code=status.HTTP_400_BAD_REQUEST,\n                    detail=(f\"MCP server '{name}' sets environment variable '{env_name}', which would run arbitrary code at process startup.\"),\n                )\n\n\ndef _mask_server_config(server: McpServerConfigResponse) -> McpServerConfigResponse:\n    \"\"\"Return a copy of server config with sensitive fields masked.\n\n    Masks env values, header values, and removes OAuth secrets so they\n    are not exposed through the GET API endpoint.\n    \"\"\"\n    masked_env = {k: _MASKED_VALUE for k in server.env}\n    masked_headers = {k: _MASKED_VALUE for k in server.headers}\n    masked_oauth = None\n    if server.oauth is not None:\n        masked_oauth = server.oauth.model_copy(\n            update={\n                \"client_secret\": None,","sourceCodeStart":604,"sourceCodeEnd":640,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/mcp.py#L604-L640","documentation":"400 raised when a stdio MCP server definition sets an environment variable whose name (case-insensitive) is in _CODE_INJECTING_ENV_VARS — variables like PYTHONSTARTUP, NODE_OPTIONS, LD_PRELOAD, PERL5OPT that cause code to run at process startup. This closes the gap where an allowlisted binary is hijacked via its runtime's startup hooks.","triggerScenarios":"Submitting env: {\"NODE_OPTIONS\": \"--require ./hook.js\"} or {\"PYTHONSTARTUP\": \"script.py\"} with a stdio server; copying a Docker/env-file setup that relies on these tuning variables into MCP config.","commonSituations":"Legitimate-looking performance/debug tuning (NODE_OPTIONS=--max-old-space-size is still rejected as a class); hardening bypass attempts; env blocks copied from local development shells.","solutions":["Remove the code-injecting variable from the server's env block","Achieve the effect differently: set runtime options via launcher args, or configure the server package itself","If a variable is genuinely required and safe, ask the operator to run that server outside the API-managed path"],"exampleFix":"# before\n{\"command\": \"npx\", \"args\": [\"-y\", \"srv\"], \"env\": {\"NODE_OPTIONS\": \"--require ./preload.js\"}}\n# after\n{\"command\": \"npx\", \"args\": [\"-y\", \"srv\"], \"env\": {\"SRV_CONFIG_PATH\": \"/etc/srv/config.json\"}}","handlingStrategy":"validation","validationCode":"const CODE_INJECTING = new Set(['PYTHONSTARTUP','NODE_OPTIONS','LD_PRELOAD','LD_AUDIT','PERL5OPT','RUBYOPT','JAVA_TOOL_OPTIONS']);\nfunction assertSafeEnv(env: Record<string, string>) { for (const k of Object.keys(env)) if (CODE_INJECTING.has(k.trim().toUpperCase())) throw new Error(`env var ${k} can inject startup code`); }","typeGuard":"function isCodeInjectingEnvName(name: string): boolean { return ['PYTHONSTARTUP','NODE_OPTIONS','LD_PRELOAD','PERL5OPT','RUBYOPT','JAVA_TOOL_OPTIONS'].includes(name.trim().toUpperCase()); }","tryCatchPattern":"null","preventionTips":["Do not copy your local shell env into MCP server env blocks","Express runtime tuning via launcher args or the server package's own config","Treat any startup-hook env var as rejected by design, even for benign values"],"tags":["mcp","security","env-vars","code-injection","http-400"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}