# GHSA-4gph-2hhr-5mwg: Envoy AI Proxy - MCP Message Smuggling Vulnerability

> Attackers can bypass security controls in Envoy AI Gateway by smuggling MCP messages via case-variant JSON-RPC fields, altering request routing.

- **Severity:** Not scored
- **Exploited in the wild:** Not known
- **Login needed:** Any signed-in user
- **Attackable:** Over the internet
- **Victim action needed:** Not needed
- **Fix available:** Yes
- **Published:** 19 May 2026
- **Also known as:** GO-2026-5121

## What is GHSA-4gph-2hhr-5mwg?

GHSA-4gph-2hhr-5mwg is a vulnerability in github.com/envoyproxy/ai-gateway, published on 19 May 2026. Any signed-in user can exploit it over the network, with no action from the victim.

### Official description

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/specification

```
[...]
All member names exchanged between the Client and the Server that are considered for matching of any kind should be considered to be case-sensitive. The terms function, method, and procedure can be assumed to be interchangeable.
```

The 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:
1. **Incoming MCP Message**:

```
{
    id: 1,
    jsonrpc: "2.0",
    method: "tools/call",
    params: {
        name: "backend__greet",
        Name: "backend__secretTool",
        arguments: {
            name: "World!"
        },
        Arguments: {
            name: "Exploit"
        }
    }
}
```

2. **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`
3.  **Overwrites** the authorized "backend__greet" value from the valid `name` field with the malicious value from the `Name` field
4.  **Normalizes** the injected "backend__secretTool" value (from the invalid `Name` field)
5.  **Re-serializes** the request into a new, valid MCP JRPC payload (`{"name": "backend__secretTool"}`) and forwards it upstream

This "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 Analysis

The root cause is a parser differential combined with serialization quirk typical of Go-based JSON parsers:

1. **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
2. **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 receiver

The 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`
```go
import (
	sonicjson "github.com/bytedance/sonic"
)
var (
	Unmarshal = sonicjson.ConfigDefault.Unmarshal
    Marshal   = sonicjson.ConfigDefault.Marshal
)
``` 

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/call

The 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`
```go
...
	body, err := io.ReadAll(r.Body)
	if err != nil {
		errType = metrics.MCPErrorInternal
		onErrorResponse(w, http.StatusBadRequest, err.Error())
		return
	}

	rawMsg, err := jsonrpc.DecodeMessage(body)
    ...
```

If the request method is `tools/call`, the following code is executed at `ai-gateway/internal/mcpproxy/handlers.go:366`

```go
		case "tools/call":
			params = &mcp.CallToolParams{}
			span, err = parseParamsAndMaybeStartSpan(ctx, m, msg, params, r.Header)
			if err != nil {
				errType = metrics.MCPErrorInvalidParam
				m.l.Error("Failed to unmarshal params", slog.String("method", msg.Method), slog.String("error", err.Error()))
				onErrorResponse(w, http.StatusBadRequest, "invalid params")
				return
			}
			err = m.handleToolCallRequest(ctx, s, w, msg, params.(*mcp.CallToolParams), span, r)
```

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`
```go
func (m *mcpRequestContext) handleToolCallRequest(ctx context.Context, s *session, w http.ResponseWriter, req *jsonrpc.Request, p *mcp.CallToolParams, span tracingapi.MCPSpan, r *http.Request) error {

	// ... REDACTED CODE TO Enforce authentication and authorizationif required by the route ...

	// Send the request to the MCP backend listener.
	p.Name = toolName
	param, _ := json.Marshal(p)
	if m.l.Enabled(ctx, slog.LevelDebug) {
		logger := m.l.With(slog.String("tool", p.Name), slog.Any("session", cse))
		logger.Debug("Routing to backend")
	}
	if span != nil {
		span.RecordRouteToBackend(backend.Name, string(cse.sessionID), false)
	}
	req.Params = param
	return m.invokeAndProxyResponse(ctx, s, w, backend, cse, req)
}
```

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 Types

The 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 Concept

Payload:

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "backend__greet",      // SAFE: Validated & A

## Which versions are affected by GHSA-4gph-2hhr-5mwg?

3 open source packages ship an affected version, including github.com/envoyproxy/ai-gateway.


| Package | Ecosystem | Affected | Fixed in |
| --- | --- | --- | --- |
| `github.com/envoyproxy/ai-gateway` | Go | All versions | 0.6.0 |
| `github.com/envoyproxy/ai-gateway` | Go | All versions | 0.6.0 |
| `github.com/envoyproxy/ai-gateway` | Go | All versions | 0.6.0 |

## How do I fix GHSA-4gph-2hhr-5mwg?

Upgrade github.com/envoyproxy/ai-gateway to 0.6.0 or later.

## Is GHSA-4gph-2hhr-5mwg being exploited?

There is no known exploitation of GHSA-4gph-2hhr-5mwg in the wild and no public exploit code.

## Fix prompt for AI coding agents

```text
Check this codebase for GHSA-4gph-2hhr-5mwg and fix it if it is affected.

What it is: GHSA-4gph-2hhr-5mwg is a vulnerability in github.com/envoyproxy/ai-gateway, published on 19 May 2026. Any signed-in user can exploit it over the network, with no action from the victim.
Exploitation: There is no known exploitation of GHSA-4gph-2hhr-5mwg in the wild and no public exploit code.

Affected packages and fixed versions:
- github.com/envoyproxy/ai-gateway (Go): affected all versions; fixed in 0.6.0
- github.com/envoyproxy/ai-gateway (Go): affected all versions; fixed in 0.6.0
- github.com/envoyproxy/ai-gateway (Go): affected all versions; fixed in 0.6.0

Task:
1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.
2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.
3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.
4. Run the tests and summarise what changed and why.
5. If nothing in the project is affected, say so and change nothing.

Reference: https://insights.sbomify.com/GHSA-4gph-2hhr-5mwg/ (Markdown: https://insights.sbomify.com/GHSA-4gph-2hhr-5mwg/index.md)
```

## Sources

- OSV: https://osv.dev/vulnerability/GHSA-4gph-2hhr-5mwg

---
From sbomify Insights: https://insights.sbomify.com/GHSA-4gph-2hhr-5mwg/
Summaries are generated and may contain mistakes; the official description above is the record.
