GHSA-4gph-2hhr-5mwg: Envoy AI Proxy - MCP Message Smuggling Vulnerability
Envoy AI Gateway was found to be affected by a protocol parser differential vulnerability due to improper implementation of the JSON-RPC 2.0 specification. Such differential causes a MCP message alteration, potentially causing a bypass of security controls in a multi-layered architecture.According to the JSON RPC Spec used by Model Context Protocol, JSON RPC should be case sensitive https://www.jsonrpc.org/specificationThe AI Gateway is accepting and processing case-variant fields that compliant MCP implementations correctly ignore. Crucially, Envoy does not just "pass through" the message by acting as a transparent proxy, it alters the traffic, allowing smuggling of unwanted requests.The following steps represent the incoming message alteration:**Incoming MCP Message**:**Parses** the request, picking the non-standard `Name` field over the authorized `name` field due to internal case-insentitive parsing by libraries such as `modelcontextprotocol/go-sdk/jsonrpc` and `github.com/bytedance/sonic`**Overwrites** the authorized "backend__greet" value from the valid `name` field with the malicious value from the `Name` field**Normalizes** the injected "backend__secretTool" value (from the invalid `Name` field)**Re-serializes** the request into a new, valid MCP JRPC payload (`{"name": "backend__secretTool"}`) and forwards it upstreamThis "smuggling" effect means Envoy actively transforms a request that might have been checked by any prior MCP-compliant implementation into a request that is **valid and altered** (from the perspective of the upstream backend), effectively introducing protocol modifications that may allow bypassing any prior authorization layer.Root Cause AnalysisThe root cause is a parser differential combined with serialization quirk typical of Go-based JSON parsers:**Case-Insensitive Unmarshaling** - When parsing a JSON key into a struct field, Go's `json.Unmarshal` looks for an a case-insensitive match. Go matches "Name" to the struct tag `json:"name"`. If `"name": "safe"` is also present, the last key processed wins, allowing an attacker to inject a different tool name when the MCP message reaches the Go-SDK parsing**Strict Struct-Tag Marshaling** - When converting a struct back to JSON, Go always uses the exact key specified in the Struct `json:"..."` tag. Consequently, an overwritten value from a cased field could be stored in a proper lowercased parameter, later processed by a spec-compliant MCP message receiverThe vulnerability involves the usage of the `jsonrpc` module of `github.com/modelcontextprotocol/go-sdk`, which is not following the MCP mandated JSON RPC spec for messages parsing, using case insensitive matching.The non-compliant parsing primitive is `jsonrpc.DecodeMessage`, it is widely used to parse the incoming MCP messages.
See at:`ai-gateway/internal/mcpproxy/handlers.go:242,739``ai-gateway/internal/mcpproxy/mcpproxy.go:303``ai-gateway/internal/mcpproxy/session.go:409``ai-gateway/internal/mcpproxy/sse.go:88`Consequently, internals relying on objects parsed with the cited primitive are using case-insentive parsing, also subject to Unicode to ASCII Folding.Furthermore, the internal logic is also relying on the `internal/json` package, acting as a wrapper around `github.com/bytedance/sonic` (Sonic), a high-performance JSON library that defaults to loose, case-insensitive unmarshalling.**File**: `internal/json/json.go`In combination with the above mentioned spec departure, the message MCP message reconstruction logic is causing an alteration of the protocol calls passing through the gateway.Example Vulnerable Data Flow - tools/callThe alteration occurs in `ai-gateway/internal/mcpproxy/handlers.go:180` during the processing of a function `servePOST`.As an example, we can focus on the processing of incoming MCP `tools/call` requests.When the gateway receives a JSON-RPC request, it executes `servePOST` function, which then calls `jsonrpc.DecodeMessage` to parse the body of the bytes read from the request.See at `ai-gateway/internal/mcpproxy/handlers.go:235-242`If the request method is `tools/call`, the following code is executed at `ai-gateway/internal/mcpproxy/handlers.go:366`At this point, the `params` object is a `mcp.CallToolParams` struct incorrectly parsed by Anthropic's `jsonrpc.DecodeMessage` as case insentitive object. The `params` object is then passed to `handleToolCallRequest` function, which will execute the tool call.See at definition of `handleToolCallRequest` at `ai-gateway/internal/mcpproxy/handlers.go:638`In the code pattern above, the final alteration of the MCP message happens. The function is using as `json` parser the wrapper around `sonic` (`ai-gateway/internal/json`), which is a case-insensitive parser, to reserialize the parameter struct with `json.Marshal`.When the struct is **re-marshaled**, it uses the exact casing defined in the struct's JSON tag. This allows an attacker to "smuggle" a malicious value through a non-standard key name, bypassing case-sensitive filters on previous stages of the request handling by other MCP-compliant components.In conclusion, the described MCP message alteration is ensuring that the final proxied version by Envoy-AI Gateway will become "canonical" and delivered upstream with smuggled malicious values.Other Message TypesThe Parser Differential is not limited to `tools/call`. It is a pervasive design issue caused by the Go SDK and Sonic manipulation of MCP Messages.List of smuggling sinks:`tools/call``prompts/get``resources/read`In conclusion, the reported smuggling problem is systemic in the AI Proxy.Proof of ConceptPayload:Scenario:The full PoC can be downloaded as `envoy-security@googlegroups.com` at: https://doyensec.sendsafely.com/receive/?thread=3574-4CPK&packageCode=lAXsPv8NK0tR0VTEXno9DZjFB5Ph3eKaSER6rpiirvk#keyCode=R_jMV3ENlORCmzkka3jwupPgsUq-TqNOAoizUqzlWHgPrerequisites are having installed: Minikube, Docker and Helm.In order to reproduce the scenario, it is sufficient to run the described stack with the commands below:The PoC will:Start a MCP-cmpliant downstream proxy that should block requests to `backend__secretTool`Start the Envoy AI Gateway and configure it as basic routerStart an upstream MCP server exposing `backend__secretTool` and `backend_greet`Send MCP `tools/call` requests to the downstream proxy to demonstrate the vulnerabilityIt is also possible to inspect the full traffic proccessing logs at `PoC/logs/`.The example below shows the final PoC smuggled message received and executed by the upstream MCP Server:While below is reported the log of the downstream compliant proxy that allowed the message as compliant `greet` command before it was smuggled by Envoy AI Proxy:ImpactThis vulnerability makes downstream authorization layers ineffective when Envoy AI Gateway is used as a router. By altering the message content, Envoy effectively acts as a "Confused Deputy" that:**Trusted Input**: Takes input trusted by the other MCP-compliant actors**Malicious Transformation**: Converts it into a totally different, but compliant, MCP message. Violating the transparency nature of proxies and altering a valid request into a malicious one**Trusted Output**: Sends it off as a valid request to the upstream backendAuthentication and Authorization guarantees provided by prior actors or MCP manipulations are nullified because the original message **is not** the message the target Backend receives.RemediationStrict Protocol Compliance
Envoy AI Gateway must enforce **Strict Case Sensitivity** during JSON unmarshalling to comply with JSON-RPC 2.0.Reject Unknown Fields In Protocol Reserved Areas
Enable `DisallowUnknownFields`.Preserve Integrity
If Envoy acts as a transparent router, it should avoid unnecessary re-serialization of the payload body unless modification is explicitly required and safe. If normalization is required, it must be lossless and strictly validated.It should be highlighted that after our root-cause analysis, `github.com/modelcontextprotocol/go-sdk` is ultimately responsible for the initial part the issue. As a result, we would expect the maintainers to fix the vulnerability upstream.As a general recommendation, Envoy AI Gateway should use a JSON RPC parser and subsequent JSON parsing strategies in `sonic` which are following the SPEC to prevent the differentials, forcing the case sensitive matching on MCP messages.Doyensec has already reported the Go-SDK violation of the JSON RPC Specification via Hackerone.
CVSS v4.0: 6.3