Skip to main content

validate_server_config

Function validate_server_config 

Source
pub fn validate_server_config(config: &ServerConfig) -> Result<()>
Expand description

Validates a ServerConfig for safe execution, dispatching on transport type.

This function performs comprehensive security validation before a config is used to connect to a server. It validates:

  1. Stdio transport: command (absolute path or binary name), arguments, and environment variables.
  2. Http/Sse transport: URL presence and scheme, and HTTP header names/values.
  3. Timeouts: connect_timeout/discover_timeout checked against bounds, for all transports.

§Security Rules

  • Forbidden chars in command/args: ;, |, &, >, <, `, $, (, ), \n, \r
  • Env name charset: must match [A-Za-z_][A-Za-z0-9_]* (POSIX/Windows environment variable identifier convention); rejects non-ASCII Unicode confusables (e.g. U+0131 ı, U+017F ſ) that could otherwise dodge the ASCII-only case-insensitive comparison below while still resolving as the forbidden name on Windows
  • Forbidden env names: dynamic-linker (LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_*), PATH, and interpreter hijack vectors (NODE_OPTIONS, BASH_ENV, PYTHONPATH, PYTHONSTARTUP, RUBYOPT, PERL5OPT, JAVA_TOOL_OPTIONS), matched case-insensitively — see the FORBIDDEN_ENV_NAMES constant’s doc comment in this module’s source for the full threat-model note
  • Absolute paths: Must exist and be executable
  • Binary names: Allowed (resolved via PATH at runtime)
  • URL scheme: Must be http:// or https://
  • Header names/values: Must not contain control characters
  • Timeout bounds: connect_timeout/discover_timeout must be greater than zero and at most MAX_TIMEOUT (600s)
  • Element counts/lengths (denial-of-service protection, CWE-400) — see this module’s validate_stdio_size_bounds/validate_network_size_bounds: at most MAX_ARG_COUNT args, MAX_ENV_COUNT env vars, and MAX_HEADER_COUNT headers; at most MAX_ARG_LEN bytes per command/argument/env-name/header-name, MAX_ENV_VALUE_LEN bytes per env value, MAX_HEADER_VALUE_LEN bytes per header value, and MAX_URL_LEN bytes for the url field

§Errors

Returns Error::SecurityViolation if:

  • Command is empty or whitespace
  • Command/args contain shell metacharacters
  • Absolute path does not exist or is not executable
  • Environment variable name is forbidden, or outside the [A-Za-z_][A-Za-z0-9_]* charset
  • URL scheme is not http:///https://, or a header name/value contains control characters

Returns Error::ValidationError if:

  • URL is missing for Http/Sse transport
  • connect_timeout or discover_timeout is zero
  • connect_timeout or discover_timeout exceeds MAX_TIMEOUT (600s)

§Examples

use mcp_execution_core::{ServerConfig, validate_server_config};

// Valid: binary name
let config = ServerConfig::builder()
    .command("docker".to_string())
    .build()
    .unwrap();
assert!(validate_server_config(&config).is_ok());

// Invalid: forbidden env var — `ServerConfigBuilder::build()` already
// rejects this, so no unvalidated `ServerConfig` reaches this function.
let err = ServerConfig::builder()
    .command("docker".to_string())
    .env("LD_PRELOAD".to_string(), "/evil.so".to_string())
    .build()
    .unwrap_err();
assert!(err.is_security_error());

// Valid: HTTP transport
let config = ServerConfig::builder()
    .http_transport("https://api.example.com/mcp".to_string())
    .build()
    .unwrap();
assert!(validate_server_config(&config).is_ok());

§Security Considerations

  • Binary names are allowed and resolved via PATH at runtime
  • Absolute paths undergo strict validation (existence, permissions)
  • All arguments are validated separately to prevent injection
  • Environment variables are checked against forbidden names
  • Header values are never echoed into error messages, since they routinely carry secrets such as bearer tokens
  • Header names are never echoed either, once rejected: a Name=Value or Name: Value CLI argument can be mis-split on the wrong separator, leaving a full secret value in the “name” position — the token-charset error, the duplicate-header-name error, and the header-value control-character error all omit the name for this reason
  • There is no infinite-timeout option: 0 is always rejected, since an unbounded wait would let a hung server block this non-interactive tool forever (see the validate_timeout design note in this module)