Skip to main content

MCP-005 Cleartext or unauthenticated remote endpoint

Remote MCP servers (the url / endpoint form rather than the local command form) ship every prompt the model issues, every tool call the model triggers, and every result the server returns across the network connection declared in the host config. When the URL is http:// instead of https://, all of that data travels unencrypted: an attacker on the wire sees the whole conversation, including any credentials the host config inlines. When the URL is https:// but no auth credential is declared alongside, the server may be world-callable: anyone who can dial the URL can talk to it.

What Vulkro detects

Rule fires in two shapes:

  • Cleartext: URL starts with http:// and does NOT point at a loopback host (localhost, 127.0.0.1, [::1]). Severity: High. Confidence: High. Evidence signal: mcp-server-cleartext-http, weight 0.7, source Pattern. Fires regardless of whether auth is declared because the auth credential itself travels in cleartext.
  • Unauthenticated HTTPS: URL starts with https:// and the server has no recognisable auth indicator (no env key matching Authorization, Bearer, Token, API_KEY, <X>_API_KEY, <X>_TOKEN, secret; no arg matching Authorization:, Bearer , --api-key, --token, --auth). Severity: Medium. Confidence: Medium. Evidence signal: mcp-server-unauthenticated-https, weight 0.5, source Heuristic. Absence of evidence is not evidence of absence; the heuristic could miss an unusual auth shape.

Loopback exemption: http://localhost:<port> and http://127.0.0.1:<port> are exempt from the cleartext finding. Local development is a legitimate use of plain HTTP.

Non-compliant config

{
"mcpServers": {
"remote-tool": {
"type": "http",
"url": "http://mcp.example.com/v1"
},
"open-listener": {
"type": "http",
"url": "https://mcp.example.com/v1"
}
}
}

The first entry leaks every prompt over the wire. The second declares no Authorization or API-key indicator; the server may accept any caller.

Compliant config

{
"mcpServers": {
"remote-tool": {
"type": "http",
"url": "https://mcp.example.com/v1",
"env": {
"Authorization": "Bearer ${MCP_TOKEN}"
}
},
"internal-tool": {
"type": "http",
"url": "https://mcp.internal.corp/v1",
"env": {
"API_KEY": "${INTERNAL_MCP_KEY}"
}
}
}
}

Remediation

  1. Switch the endpoint to https://. If the upstream genuinely runs HTTP only, terminate TLS in front of it (caddy, nginx, an ssh tunnel) rather than connecting in cleartext.
  2. Add an authentication indicator: an Authorization: Bearer ${TOKEN} env entry, an API_KEY env var, or an --api-key / --auth CLI arg the server understands.
  3. If the upstream is genuinely public and unauthenticated, document the trust assumption in your README so the next reviewer doesn't have to rediscover it.
  4. For local development, prefer http://localhost:<port> (which is exempt from the cleartext finding) over connecting to a remote dev box in cleartext.

See also

  • vulkro mcp-audit - parent CLI command.
  • MCP-004 - the rule that catches the literal-in-env shape of the auth credentials this rule asks you to add.
  • Confidence model - what High, Medium, Low mean.

References