bytedance/deer-flow · error · HTTPException

MCP server '{name}' passes '{exec_flag}' to '{command_name}'

Error message

MCP server '{name}' passes '{exec_flag}' to '{command_name}', which would run arbitrary code. Point the server at a package or module instead.

What it means

400 raised when the args passed to an allowlisted launcher contain a flag that turns it into an arbitrary code executor — e.g. node/python -e, npx -c, or uv's --with/extras forms evaluated unsafely. The screening function _arbitrary_exec_arg detects these flags so an API caller cannot use an approved binary as a general code runner.

Source

Thrown at backend/app/gateway/routers/mcp.py:615

    allowlisted binary into an arbitrary code evaluator.
    """
    allowed_commands = _allowed_stdio_commands()
    for name, server in request.mcp_servers.items():
        transport_type = (server.type or "stdio").lower()
        if transport_type != "stdio":
            continue

        command_name = _stdio_command_name(server.command, server_name=name)
        if command_name not in allowed_commands:
            allowed = ", ".join(sorted(allowed_commands)) or "<none>"
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=(f"MCP server '{name}' uses disallowed stdio command '{command_name}'. Allowed commands: {allowed}. Configure {_MCP_STDIO_COMMAND_ALLOWLIST_ENV} to extend this list."),
            )

        exec_flag = _arbitrary_exec_arg(server.args, command=command_name)
        if exec_flag is not None:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                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."),
            )

        for env_name in server.env:
            if env_name.strip().upper() in _CODE_INJECTING_ENV_VARS:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=(f"MCP server '{name}' sets environment variable '{env_name}', which would run arbitrary code at process startup."),
                )


def _mask_server_config(server: McpServerConfigResponse) -> McpServerConfigResponse:
    """Return a copy of server config with sensitive fields masked.

    Masks env values, header values, and removes OAuth secrets so they
    are not exposed through the GET API endpoint.
    """

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Package the code as a module/package and point the launcher at it (e.g. uvx --from ./pkg server, npx -y package)
  2. Remove -e/-c style flags from args entirely
  3. Run genuinely custom code as a local MCP server via a non-API mechanism (operator-managed config) rather than through the API boundary

Example fix

# before
{"command": "node", "args": ["-e", "require('my-server').start()"]}
# after
{"command": "npx", "args": ["-y", "my-mcp-server"]}
Defensive patterns

Strategy: validation

Validate before calling

const EXEC_FLAGS = new Set(['-e', '--eval', '-c', '--command']);
function assertNoExecFlags(args: string[]) { for (const a of args) if (EXEC_FLAGS.has(a)) throw new Error(`arg ${a} turns the launcher into an arbitrary code runner; use a package/module instead`); }

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Submitting args like ['-c', 'import os; ...'] to python, ['-e', 'script'] to node, or any eval-style flag detected for the chosen command; adapting a CLI recipe that uses -e into the MCP args array.

Common situations: Trying to shim a server with an inline script instead of packaging it; porting docker-style one-liners into MCP args; misunderstanding that the allowlist approves the binary, not arbitrary invocations of it.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/adc06a612f0e64f9. Report an issue: GitHub.