MCP Shell Server

repository·main·Indexed 41 days ago

https://github.com/tumf/mcp-shell-server

A Model Context Protocol (MCP) implementation that provides a controlled way to execute system commands. It allows MCP clients to run allowlisted commands using argv arrays to avoid shell-string interpretation, supports stdin, and provides contained redirection within a specified working directory. The server enforces execution limits, including timeouts and output byte caps, and emits structured audit records for all command invocations.

Tokens
6.5K
Snippets
18
Records
32
Agent score
49%

What's inside MCP Shell Server

  1. Overview of MCP Shell Server

    main

    MCP Shell Server is a trusted execution server implementing the Model Context Protocol (MCP). It allows an MCP client to run allowlisted commands using argv arrays (avoiding shell-string interpretation), supports stdin input, and provides contained redirection (<, >, >>) within a specified working directory.

    Important Security Note: This package is not a sandbox. When you allow a command, that program runs with the server process's existing OS authority (filesystem, network, and credentials). It is highly recommended to run this server inside an external OS boundary (like a container, VM, or jail) if it processes untrusted input.

  2. Audit record requirements for command invocations

    main

    The MCP Shell Server is required to emit structured audit records for all command invocation outcomes. These records are designed to provide visibility into command execution while maintaining security by redacting raw command output and unredacted secrets.

    Audit records are generated for three primary scenarios:

    1. Successful Invocations: Includes timestamp, command name, redacted argv, resolved directory, output byte counts, return code, duration, and success result.
    2. Rejected Invocations: Triggered when a command fails validation before a subprocess is created. Includes the rejection result and redacted metadata for incident review.
    3. Terminated Invocations: Triggered when a command times out or exceeds output limits. Includes the timeout or output-cap result and relevant limit metadata.

    Security Note: To prevent data leakage, the server automatically redacts raw stdout/stderr and replaces secret-like metadata with redacted placeholders in all audit records.

  3. Execute commands using argv arrays

    main

    To prevent shell injection, the server executes commands as argv arrays rather than shell-interpreted strings.

    • Single Commands: Pass the command and its arguments as separate elements in an array: ['echo', 'hello'].
    • Pipelines: You can execute pipelines by providing segments as array elements: ['echo', 'hello', '|', 'grep', 'h']. The server validates each segment.
    • Injection Prevention: The server will reject any command segment containing shell metacharacters like ; to prevent unauthorized command chaining.
    // Example of a valid pipeline execution structure
    ["echo", "hello", "|", "grep", "h"]
  4. Understand the Shell Execution Security Model

    main

    The mcp-shell-server operates on a trusted-execution boundary. It does not provide a sandbox; instead, it delegates the server process's existing OS authority to allowed programs.

    Key Security Principles:

    • Command Admission: Allowlisting controls which executable names can be launched directly. It does not contain the behavior of the allowed program itself (e.g., an allowed program can still access the network or filesystem within the server's OS permissions).
    • External Isolation Required: If the MCP client (like an LLM) processes untrusted prompts, files, or repositories, you must use external OS-level isolation (containers, VMs, etc.) for the server. Client authentication is not a substitute for OS isolation.
    • Defense-in-Depth: The server implements specific protections (like argument rejection and redirection containment) as additional layers, but these are not exhaustive containment measures.
  5. Understand the Trusted Execution Contract

    main

    The server enforces boundaries on its own behavior, but it does not provide full process containment.

    What the server controls:

    • Which executable names are launched via ALLOW_COMMANDS and ALLOW_PATTERNS.
    • Process creation via argv (no shell-string interpretation).
    • Redirection (<, >, >>) limited to the requested working directory.
    • The child environment (minimal allowlisted environment).
    • Execution limits (timeouts and output byte caps).
    • Structured audit logging.

    What the server does NOT control:

    • Child processes spawned by an allowed program.
    • Program-specific interpreters, plugins, or expression languages.
    • Filesystem access or network access performed by the allowed program itself.
    • Configuration files or environment-driven behavior of the allowed program.
  6. Configure ALLOW_PATTERNS for exact command matching

    main

    When configuring ALLOW_PATTERNS, the server requires exact command-name matching. Patterns must match the full command name and cannot use prefix matching to grant permissions. For example, if you allow ls, the server will permit ls but will reject lsof because it is not an exact match. Additionally, any command string attempting to use shell metacharacters to bypass matching will be rejected before process creation.

    // Allowed: Exact match
    ALLOW_PATTERNS: ls
    // Rejected: Prefix match
    Command: lsof
  7. Understand the child process environment isolation policy

    main

    The mcp-shell-server implements a strict security contract regarding environment variables. To prevent accidental leakage of sensitive information, child processes MUST NOT inherit the server's parent environment by default.

    Key behaviors of the isolation policy:

    1. Default Exclusion: Any secret or sensitive variable present in the server's environment (e.g., SECRET_TOKEN) is automatically excluded from child processes unless explicitly configured otherwise.
    2. Explicit Allowlisting: Only variables that are explicitly documented in the configuration allowlist are permitted to be passed to child processes.
    3. Injection Rejection: Any attempt by a caller or internal path to inject environment values that are not present in the allowlist will be rejected or ignored by the server to maintain the integrity of the isolated environment.
  8. Understand command argument and bypass protections

    main

    The MCP Shell Server implements a strict command policy that validates arguments to prevent execution bypasses, even if the base command is allowlisted. The server rejects several categories of dangerous argument patterns:

    • Git Configuration Overrides: Any use of -c <name=value> or -c<name=value> is categorically disallowed to prevent command-scoped configuration escapes (e.g., git -c core.fsmonitor=touch marker status). This includes even benign-looking configurations.
    • Persistent Configuration: Commands like git config that attempt to write persistent settings (e.g., git config alias.pwn '!sh -c id') are rejected.
    • Command Wrappers: Tools used to execute other commands (e.g., timeout, sh, sudo) are rejected if they are used to wrap a non-allowlisted command.
    • GNU Sort Bypasses: For sort or gsort, the server rejects options that interact with the external environment, such as --compress-program, -o (direct output to a path), --files0-from, -T (temporary directory), or --temporary-directory when used with untrusted paths.
    • Option Permutation: The server validates options regardless of their position in the command string. An option like -o /tmp/outside will be rejected even if it appears after a filename operand.
    • Operand Delimiters: The server respects the -- delimiter. Any tokens appearing after -- are treated as filename operands rather than options, preventing option-based bypasses.
  9. Understand command execution limits and safety guarantees

    main

    The MCP Shell Server enforces strict execution limits to prevent runaway processes and resource exhaustion. These limits apply to every command invocation, even if the client does not provide explicit arguments.

    Timeout Enforcement

    • Default Timeouts: If a client omits the timeout argument, the server applies a configured default timeout. If the command exceeds this, the server terminates the process and returns a timeout outcome.
    • Timeout Bounding: If a client requests a timeout that exceeds the server's configured maximum, the server will either clamp the value to the maximum allowed or reject the request.
    • Process Layer Enforcement: The timeout is enforced at the process execution layer once command execution begins.

    Output Bounds

    • Output Caps: The server enforces byte limits on stdout and stderr. If a command produces output exceeding the configured byte limit, the server will truncate the output or terminate the command and report an explicit capped/truncated outcome.

    Process Cleanup

    • Deterministic Termination: When a command is stopped due to a timeout or output limit violation, the server ensures the child process is terminated and reaped to prevent orphaned processes.
  10. Configure Execution Limits (Timeout and Output)

    main

    To prevent resource exhaustion, every command is bounded by limits even if the client does not specify them.

    • Timeouts: If a client omits a timeout argument, the server applies a configured default. If the command exceeds this, the server terminates it and returns a timeout outcome.
    • Output Limits: To prevent unbounded buffering, the server enforces an output byte limit. If reached, the server terminates or truncates the command and reports a capped/truncated outcome.
  11. How pipeline execution and argument preservation work

    main

    The MCP Shell Server executes pipelines by treating each segment as an argv array. To prevent shell injection and ensure security, the server follows these rules:

    1. Discrete Pipe Recognition: The server only recognizes a pipeline segment break when it encounters a literal | as a standalone element in the argv array.
    2. Literal Argument Preservation: Pipe characters (|) embedded within an argument string (e.g., in a regex or an awk command) are treated as literal data and do not trigger new pipeline segments.
    3. No Shell Interpretation: The server does not execute user-controlled strings through a shell. This prevents shell metacharacter injection (like ;, &&, or ||) from executing unintended commands.
    4. Atomic Validation: The entire pipeline is validated against the command policy before any subprocesses are created. If any single segment in the pipeline is disallowed, the entire execution is rejected immediately.
    // Example of a valid pipeline execution via argv array
    // The '|' is a discrete element triggering a segment break
    ["echo", "hello", "|", "grep", "h"]
    
    // Example of a literal pipe preserved as data
    // The '|' is part of the string and does NOT trigger a segment break
    ["grep", "-E", "error|warning", "file.txt"]
  12. Understand Environment Isolation and Audit Logging

    main

    The server protects sensitive data through environment isolation and structured logging.

    • Environment Isolation: Child processes do not inherit the server's environment wholesale. They receive only a minimal explicit environment. Server secrets (e.g., SECRET_TOKEN) are not visible to child processes unless explicitly allowlisted.
    • Audit Logs: The server emits structured logs for all outcomes (success, rejection, timeout, output-cap, or error).
    • Secret Redaction: To prevent leakage, audit logs automatically redact secret-like values and metadata from command arguments and environment info.