SECURITY ADVISORY / 01

CVE-2026-16498 Exploit & Vulnerability Analysis

Complete CVE-2026-16498 security advisory with proof of concept (PoC), exploit details, and patch analysis for terraform-mcp-server.

terraform-mcp-server products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

An unauthenticated attacker sends a single HTTP request to any stateless streamable-HTTP endpoint. The server will reuse the Terraform token (Terraform-Token header or Authorization: Bearer <token>) from any previous request on the same connection, granting the attacker access to that user's TFE client context.

POST /mcp HTTP/1.1
Host: target.example.com
Content-Type: application/json
Authorization: Bearer attacker-token
X-Forwarded-For: 127.0.0.1

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"terraform_plan","arguments":{"workspace_id":"ws-xxx"}}}

The server returns a JSON-RPC response containing Terraform plan output or resource data, regardless of whether the Authorization header matches any session or user. The attacker observes the response body populated with Terraform state or plan results that belong to another user's workspace. If the victim user had previously authenticated on a different request sharing the same connection (e.g., behind a reverse proxy that reuses HTTP/1.1 keep-alive), the attacker inherits that cached client.

What the Patch Did

Before (vulnerable getTokenFromAuthHeader)

func getTokenFromAuthHeader(r *http.Request) string {
    authHeader := r.Header.Get("Authorization")
    if strings.HasPrefix(authHeader, "Bearer ") {
        return strings.TrimPrefix(authHeader, "Bearer ")
    }
    return ""
}

After (fixed getTokenFromAuthHeader)

func getTokenFromAuthHeader(r *http.Request) string {
    authHeader := r.Header.Get("Authorization")
    if strings.HasPrefix(authHeader, "Bearer ") {
        return strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer "))
    }
    return ""
}

The patch added a strings.TrimSpace() call around the extracted token value. This single function controls how the Authorization header's bearer token is parsed. The old code treated whitespace-padded tokens (like Bearer my-token ) as valid and extracted the padded string as-is, which could include leading/trailing spaces or entirely whitespace-only tokens. The fix normalises the extracted value by trimming whitespace, so a "blank" bearer header resolves to an empty string rather than a whitespace string that bypasses token validation.

Root Cause

This is CWE-287: Improper Authentication (specifically CWE-304: Missing Authentication for Critical Function). The dataflow begins at r.Header.Get("Authorization") in pkg/client/middleware.go line 199. The extracted token feeds into pkg/client/tfe_client.go where it is used to look up or create a TFE client via activeTfeClients.Store(sessionId, client). The trust boundary is crossed when getTokenFromAuthHeader returns a non-empty string that does not represent a valid credential — either because the Authorization header contained Bearer (all spaces) or because the token was padded with spaces that were not stripped before comparison. The fixed version makes Bearer return "", which causes the session creation logic to require a properly validated token from the environment or another header rather than accepting this invalid input as a credential.

Why It Works

The single load-bearing line is return strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer ")). Without the TrimSpace(), an attacker can send Authorization: Bearer (with trailing spaces) and the server extracts " " — a non-empty string that passes emptiness checks but matches no valid token, yet is still used to create or retrieve a cached TFE client. The engineer added TrimSpace() because the original code assumed that strings.TrimPrefix on a header value would yield either a proper token or an empty string, ignoring the fact that HTTP header values may contain extra whitespace per RFC 7230 section 3.2.6. The defence-in-depth here also includes the sha256.Sum256 token caching change in tfe_client.go (which prevents token reuse across sessions) and the ClientIPConfig validation (which prevents IP spoofing from interfering with audit logging), but the TrimSpace fix is the direct barrier that stops the credential bypass. Without it, the other controls still permit the attack by accepting whitespace-padded tokens.

Hardening Checklist

  • Normalise all HTTP header values with strings.TrimSpace before any comparison or storage — this prevents whitespace-based bypasses in Authorization headers, Content-Type, or any other client-supplied header.
  • Use strings.TrimSpace (not TrimPrefix or TrimSuffix) on token extraction to handle the full range of RFC 7230 whitespace, including tabs and multiple spaces.
  • Hash tokens with sha256.Sum256 before caching them alongside client pointers — this prevents plaintext token leakage in memory and makes cache-key comparisons constant-time.
  • Validate X-Forwarded-For against a trusted-hop count using a configurable ClientIPConfig struct with a fallback to r.RemoteAddr — never trust a single header value blindly.
  • Enforce that Terraform-Address cannot be overridden when the token comes from an Authorization header — add a http.StatusForbidden response if the user supplies both a bearer token and a custom address, preventing SSRF or multi-tenant address hijacking.

References

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-16498
  • Vendor changelog: See terraform-mcp-server 1.1.0 release notes for pkg/client/middleware.go and pkg/client/tfe_client.go changes.

Frequently asked questions about CVE-2026-16498

What is CVE-2026-16498?

CVE-2026-16498 is a security vulnerability identified in terraform-mcp-server. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-16498?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-16498. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-16498 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting terraform-mcp-server. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-16498?

CVE-2026-16498 affects terraform-mcp-server. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-16498?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for terraform-mcp-server.

What is the CVSS score for CVE-2026-16498?

The severity rating and CVSS scoring for CVE-2026-16498 affecting terraform-mcp-server is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.