TLS and Hardening¶
The HTTP transports (sse and streamable-http) enforce four independent network-layer defenses:
TLS enforcement — plaintext HTTP is rejected on non-localhost binds unless explicitly allowed.
Host header validation — every request must match the
ZSCALER_MCP_ALLOWED_HOSTSallowlist.Source IP ACL — optional
ZSCALER_MCP_ALLOWED_SOURCE_IPSallowlist for upstream filtering.CORS — controlled by
ZSCALER_MCP_ALLOWED_ORIGINS.
TLS¶
When the bind address is anything other than 127.0.0.1 / ::1 / localhost, the server requires TLS by default. The expected configuration:
export ZSCALER_MCP_TLS_CERTFILE=/path/to/server.crt
export ZSCALER_MCP_TLS_KEYFILE=/path/to/server.key
zscaler-mcp --transport streamable-http --host 0.0.0.0 --port 8443
If you start with a non-localhost bind and no TLS configured, the server refuses to start and prints a security warning. This is the right default for any deployment that isn’t a managed platform with its own TLS termination.
When TLS termination is upstream¶
Cloud Run, Azure Container Apps, AWS ALB, and most managed Kubernetes ingresses terminate TLS before the request reaches your container. The server still believes it’s on plaintext HTTP from inside, so you need to opt out of the enforcement:
export ZSCALER_MCP_ALLOW_HTTP=true
zscaler-mcp --transport streamable-http --host 0.0.0.0
Setting ZSCALER_MCP_ALLOW_HTTP=true does not disable TLS — it acknowledges that someone else is terminating it. This is the supported configuration for:
Google Cloud Run
Azure Container Apps
AWS Bedrock AgentCore (ALB)
Any Kubernetes deployment with an Ingress (NGINX, Traefik, AWS LB Controller) terminating TLS
For self-managed deployments (a single container or a single VM), keep TLS on by default and provide your own certificate.
Host header validation¶
Every HTTP request’s Host header is checked against an allowlist. This is a defense against DNS rebinding and reverse-tabnabbing attacks — the server only responds to requests addressed to a hostname you authorized.
The default allowlist is the bind address (host:port). To accept other hostnames:
export ZSCALER_MCP_ALLOWED_HOSTS="mcp.acme.com,mcp.internal.acme.com,*.cloud.run.app"
Comma-separated, wildcards supported via shell-style globbing.
To disable host validation entirely (development only):
export ZSCALER_MCP_DISABLE_HOST_VALIDATION=true
Source-IP ACL¶
An optional layer for deployments where the MCP server is reachable but should only respond to a known set of source addresses (typically an upstream proxy or NAT egress):
# Single IP
export ZSCALER_MCP_ALLOWED_SOURCE_IPS="203.0.113.5"
# Multiple IPs / CIDRs
export ZSCALER_MCP_ALLOWED_SOURCE_IPS="203.0.113.0/24,198.51.100.5,2001:db8::/32"
Requests from outside the allowlist receive 403 Forbidden before any auth check runs. Useful as an air-gap layer in front of MCP client authentication.
CORS¶
For browser-based MCP clients, the server’s CORS policy is controlled by:
export ZSCALER_MCP_ALLOWED_ORIGINS="https://app.example.com,https://internal.example.com"
Comma-separated origins. The default is empty (no cross-origin requests allowed). The MCP spec does not require browser clients — most MCP clients today are desktop apps that don’t trigger CORS checks.
Output sanitization¶
Independent of network-layer hardening, the server runs every string in every tool response through a three-stage sanitizer before serialization. This is the defense-in-depth layer against prompt injection embedded in admin-editable fields (rule descriptions, label names, location names, custom URL category names). See Output Sanitization for the full mechanism.
Defense in depth summary¶
A production deployment typically combines several of these:
# ~/zscaler-mcp.env
ZSCALER_MCP_HOST=0.0.0.0
ZSCALER_MCP_PORT=8443
# TLS (or ZSCALER_MCP_ALLOW_HTTP=true if upstream terminates)
ZSCALER_MCP_TLS_CERTFILE=/etc/ssl/zscaler-mcp.crt
ZSCALER_MCP_TLS_KEYFILE=/etc/ssl/zscaler-mcp.key
# Host header allowlist
ZSCALER_MCP_ALLOWED_HOSTS=mcp.acme.com
# Source-IP ACL (corporate egress NAT range only)
ZSCALER_MCP_ALLOWED_SOURCE_IPS=203.0.113.0/24
# Authentication
ZSCALER_MCP_AUTH_ENABLED=true
ZSCALER_MCP_AUTH_MODE=zscaler
# Writes disabled by default; opt in if needed
ZSCALER_MCP_WRITE_ENABLED=false
See also¶
MCP Client Authentication — the authentication layer that runs after host/IP/TLS checks pass.
Write Operations — limiting the blast radius of an authenticated agent.
Output Sanitization — the application-layer defense against prompt injection.