The Exploit
An unauthenticated attacker who has obtained another user's MCP session ID (e.g., from logs, network sniffing, or prior session theft) can replay that session ID to perform arbitrary Terraform operations with the victim's privileges.
## Attacker replays a stolen session ID to execute a Terraform tool call
curl -X POST https://target-server:port/mcp/streamable-http \
-H "Content-Type: application/json" \
-H "Authorization: Bearer iamvictim-session-id-12345" \
-d '{
"method": "tools/call",
"params": {
"name": "terraform_init",
"arguments": {}
},
"id": 1
}'
When the attacker sends this request, the server processes it as if the victim had initiated the command. The attacker observes a successful response with the Terraform state output, including access to sensitive infrastructure data and the ability to run destructive operations like terraform destroy.
What the Patch Did
Before (pkg/client/registry_client.go, line 25):
logger.WithField("session_id", sessionId).Info("Created HTTP client")
After (pkg/client/registry_client.go, line 25):
logger.Info("Created HTTP client")
The patch removes the session_id field from the log entry entirely. Instead of exposing the session ID as a structured log field where it could be captured by centralized logging systems or accessible to unauthorized users, the fix simply logs that an HTTP client was created without any identifying session context. This is a data minimization fix applied at the logging sink—the engineer removed the sensitive identifier from being recorded at all, rather than attempting to encrypt or hash it.
Root Cause
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor. The dataflow is straightforward: when the terraform-mcp-server creates an HTTP client for a given user's session, it logs the session ID—a secret token that authenticates the user's MCP session—into a structured log entry. Any downstream log aggregation tool, web server log viewer, or monitoring dashboard that exposes these logs allows an attacker to extract valid session IDs. The attacker then uses that session ID in the Authorization: Bearer <session_id> header to impersonate the victim. The vulnerability is that a high-entropy credential (the session ID) is treated as metadata rather than a secret, and is written to log output where it bypasses all access control boundaries. There is no encryption, hashing, or redaction applied to the session ID before logging.
Why It Works
The single load-bearing line is the entire WithField("session_id", sessionId) call. If that line were reverted, the bug would be completely un-exploitable—no session ID would appear in any log output. The engineer wrote only one new line (the trimmed call) and removed one line. However, the fix is minimal in the wrong dimension. A defense-in-depth approach would also have added:
- A log sanitizer that strips known secret patterns before writing.
- A session ID validation check that rejects requests not matching the current transport-level authentication token.
- Rate limiting on the MCP endpoint to slow down brute-force guessing of session IDs.
The engineer chose the simplest possible fix—stop logging the secret—which works perfectly against this specific leak vector but does nothing to protect against other points where the session ID might be exposed (error messages, debug pages, or other log contexts).
Hardening Checklist
- Use
Logger.WithSensitiveField()or a custom logging wrapper that automatically redacts fields matching a secret pattern (e.g., regex forsession_id,token,password) before calling the logging backend. - Enforce short-lived MCP session tokens with a maximum TTL of 15 minutes, and rotate them automatically on each new streamable-HTTP connection.
- Implement a source IP pinning check: for each session ID, record the originating IP address at creation time and reject any request using that session ID from a different IP, unless explicitly allowed by the configuration.
- Add rate limiting (e.g., 5 consecutive failed session ID guesses triggers a 10-second global lockout) to the streamable-HTTP endpoint using
golang.org/x/time/rateor similar middleware.
References
- https://nvd.nist.gov/vuln/detail/CVE-2026-16496