# `ExMCP.Transport.SecurityGuard`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/transport/security_guard.ex#L1)

Transport-layer security interceptor that enforces MCP security policies.

This module provides consistent security enforcement across all transports
by intercepting outbound requests and applying token passthrough prevention
and user consent validation.

## The trust boundary

Every outbound URL is classified as `:internal` or `:external` by comparing
its exact `(scheme, host, effective port)` origin against `:trusted_origins`.
Deliberately broad host-only matching lives in `:trusted_hosts`. External requests

  1. have their credential headers removed (token passthrough prevention), and
  2. must be approved by the configured `:consent_handler`.

`:trusted_origins` defaults to empty, `:trusted_hosts` defaults to loopback,
and `:consent_handler` defaults to `ExMCP.ConsentHandler.Deny`, so **a remote
MCP server is blocked until its exact origin is added to `:trusted_origins`**:

    config :ex_mcp, :security,
      trusted_origins: ["https://mcp.example.com"]

That single setting covers both checks — a trusted origin is never stripped
and never prompts for consent. Consent then applies only to origins the
application did not declare. See `docs/SECURITY.md`.

Both checks can be switched off individually with
`:enable_token_passthrough_prevention` and `:enable_user_consent_validation`;
prefer declaring `:trusted_origins` over disabling a control.

# `request`

```elixir
@type request() :: %{
  url: String.t(),
  headers: [{String.t(), String.t()}],
  method: String.t(),
  transport: atom(),
  user_id: String.t()
}
```

# `security_result`

```elixir
@type security_result() ::
  {:ok, sanitized_request :: map()} | {:error, security_violation :: map()}
```

# `get_security_config`

```elixir
@spec get_security_config(map()) :: map()
```

Gets the security configuration, merging provided config with defaults.

# `validate_request`

```elixir
@spec validate_request(request(), map()) :: security_result()
```

Validates a request against security policies.

This function enforces both token passthrough prevention and user consent
validation for external resource access.

## Parameters

- `request` - Standardized request structure
- `config` - Security configuration (optional, uses defaults if not provided)

## Returns

- `{:ok, sanitized_request}` - Request is allowed with potentially sanitized headers
- `{:error, security_violation}` - Request blocked by security policy

## Examples

    request = %{
      url: "https://api.example.com/data",
      headers: [{"Authorization", "Bearer token"}],
      method: "GET",
      transport: :http,
      user_id: "user123"
    }

    case SecurityGuard.validate_request(request, config) do
      {:ok, sanitized_request} ->
        # Proceed with sanitized request
        perform_request(sanitized_request)

      {:error, violation} ->
        # Handle security violation
        {:error, violation}
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
