CVE-2026-11624
Description
MCP servers prior to v0.25.0 lack host header validation, enabling DNS rebinding attacks that grant remote attackers full control over local servers.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
MCP servers prior to v0.25.0 lack host header validation, enabling DNS rebinding attacks that grant remote attackers full control over local servers.
Vulnerability
The Google MCP Toolbox (genai-toolbox) prior to version v0.25.0 lacked the ability to validate the Host header on incoming connections, making it susceptible to DNS rebinding attacks. While the server had an --allowed-origins flag for CORS validation, this was insufficient because DNS rebinding bypasses the same-origin policy by rapidly changing the DNS resolution of a domain. The vulnerability allowed an attacker to interact with a locally running Toolbox server from a remote website. The default configuration for both --allowed-origins and the newly introduced --allowed-hosts flags is "*", meaning no restrictions are applied unless explicitly configured [1][2].
Exploitation
An attacker must first trick a victim into visiting a malicious website or viewing a malicious ad. Through DNS rebinding, the attacker can make the victim's browser send requests to the local Toolbox server (typically on 127.0.0.1:5000) with a forged Host header. The server, lacking host validation, processes these requests as if they originated from a legitimate client. The attacker can then execute arbitrary actions exposed by the MCP server, such as reading or writing data, creating resources, or making HTTP requests on behalf of the victim's machine [2].
Impact
Successful exploitation gives the attacker full control over the locally running MCP server. This includes the ability to manipulate databases, steal sensitive data, create or modify resources, and perform HTTP requests from the context of the developer's computer, effectively gaining the same capabilities as an authorized AI agent [2].
Mitigation
Users must upgrade to version v0.25.0 or later, which introduced the --allowed-hosts flag. This flag allows administrators to specify a list of permitted hostnames (e.g., --allowed-hosts=127.0.0.1:5000). If either --allowed-hosts or --allowed-origins is set to "*", the server will output a startup warning about potential vulnerabilities. To fully mitigate the risk, both flags should be set to specific allowed values. No other workarounds have been published [1].
AI Insight generated on Jun 13, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2(expand)+ 1 more
- (no CPE)
- (no CPE)range: <0.25.0
Patches
117b41f64531bfeat: add allowed-hosts flag (#2254)
9 files changed · +79 −26
cmd/root.go+2 −0 modified@@ -381,7 +381,9 @@ func NewCommand(opts ...Option) *Command { flags.BoolVar(&cmd.cfg.Stdio, "stdio", false, "Listens via MCP STDIO instead of acting as a remote HTTP server.") flags.BoolVar(&cmd.cfg.DisableReload, "disable-reload", false, "Disables dynamic reloading of tools file.") flags.BoolVar(&cmd.cfg.UI, "ui", false, "Launches the Toolbox UI web server.") + // TODO: Insecure by default. Might consider updating this for v1.0.0 flags.StringSliceVar(&cmd.cfg.AllowedOrigins, "allowed-origins", []string{"*"}, "Specifies a list of origins permitted to access this server. Defaults to '*'.") + flags.StringSliceVar(&cmd.cfg.AllowedHosts, "allowed-hosts", []string{"*"}, "Specifies a list of hosts permitted to access this server. Defaults to '*'.") // wrap RunE command so that we have access to original Command object cmd.RunE = func(*cobra.Command, []string) error { return run(cmd) }
cmd/root_test.go+10 −0 modified@@ -67,6 +67,9 @@ func withDefaults(c server.ServerConfig) server.ServerConfig { if c.AllowedOrigins == nil { c.AllowedOrigins = []string{"*"} } + if c.AllowedHosts == nil { + c.AllowedHosts = []string{"*"} + } return c } @@ -220,6 +223,13 @@ func TestServerConfigFlags(t *testing.T) { AllowedOrigins: []string{"http://foo.com", "http://bar.com"}, }), }, + { + desc: "allowed hosts", + args: []string{"--allowed-hosts", "http://foo.com,http://bar.com"}, + want: withDefaults(server.ServerConfig{ + AllowedHosts: []string{"http://foo.com", "http://bar.com"}, + }), + }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) {
docs/en/how-to/deploy_docker.md+6 −1 modified@@ -68,7 +68,12 @@ networks: ``` {{< notice tip >}} -To prevent DNS rebinding attack, use the `--allowed-origins` flag to specify a +To prevent DNS rebinding attack, use the `--allowed-hosts` flag to specify a +list of hosts for validation. E.g. `command: [ "toolbox", +"--tools-file", "/config/tools.yaml", "--address", "0.0.0.0", +"--allowed-hosts", "localhost:5000"]` + +To implement CORs, use the `--allowed-origins` flag to specify a list of origins permitted to access the server. E.g. `command: [ "toolbox", "--tools-file", "/config/tools.yaml", "--address", "0.0.0.0", "--allowed-origins", "https://foo.bar"]`
docs/en/how-to/deploy_gke.md+5 −1 modified@@ -188,9 +188,13 @@ description: > path: tools.yaml ``` - {{< notice tip >}} + {{< notice tip >}} To prevent DNS rebinding attack, use the `--allowed-origins` flag to specify a list of origins permitted to access the server. E.g. `args: ["--address", +"0.0.0.0", "--allowed-hosts", "foo.bar:5000"]` + +To implement CORs, use the `--allowed-origins` flag to specify a +list of origins permitted to access the server. E.g. `args: ["--address", "0.0.0.0", "--allowed-origins", "https://foo.bar"]` {{< /notice >}}
docs/en/how-to/deploy_toolbox.md+8 −4 modified@@ -142,14 +142,18 @@ deployment will time out. ### Update deployed server to be secure -To prevent DNS rebinding attack, use the `--allowed-origins` flag to specify a -list of origins permitted to access the server. In order to do that, you will +To prevent DNS rebinding attack, use the `--allowed-hosts` flag to specify a +list of hosts. In order to do that, you will have to re-deploy the cloud run service with the new flag. +To implement CORs checks, use the `--allowed-origins` flag to specify a list of +origins permitted to access the server. + 1. Set an environment variable to the cloud run url: ```bash export URL=<cloud run url> + export HOST=<cloud run host> ``` 2. Redeploy Toolbox: @@ -160,7 +164,7 @@ have to re-deploy the cloud run service with the new flag. --service-account toolbox-identity \ --region us-central1 \ --set-secrets "/app/tools.yaml=tools:latest" \ - --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080","--allowed-origins=$URL" + --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080","--allowed-origins=$URL","--allowed-hosts=$HOST" # --allow-unauthenticated # https://cloud.google.com/run/docs/authenticating/public#gcloud ``` @@ -172,7 +176,7 @@ have to re-deploy the cloud run service with the new flag. --service-account toolbox-identity \ --region us-central1 \ --set-secrets "/app/tools.yaml=tools:latest" \ - --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080","--allowed-origins=$URL" \ + --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080","--allowed-origins=$URL","--allowed-hosts=$HOST" \ # TODO(dev): update the following to match your VPC if necessary --network default \ --subnet default
docs/en/reference/cli.md+17 −16 modified@@ -8,25 +8,26 @@ description: > ## Reference -| Flag (Short) | Flag (Long) | Description | Default | -|--------------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| -| `-a` | `--address` | Address of the interface the server will listen on. | `127.0.0.1` | -| | `--disable-reload` | Disables dynamic reloading of tools file. | | -| `-h` | `--help` | help for toolbox | | -| | `--log-level` | Specify the minimum level logged. Allowed: 'DEBUG', 'INFO', 'WARN', 'ERROR'. | `info` | -| | `--logging-format` | Specify logging format to use. Allowed: 'standard' or 'JSON'. | `standard` | -| `-p` | `--port` | Port the server will listen on. | `5000` | -| | `--prebuilt` | Use a prebuilt tool configuration by source type. See [Prebuilt Tools Reference](prebuilt-tools.md) for allowed values. | | -| | `--stdio` | Listens via MCP STDIO instead of acting as a remote HTTP server. | | -| | `--telemetry-gcp` | Enable exporting directly to Google Cloud Monitoring. | | -| | `--telemetry-otlp` | Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. 'http://127.0.0.1:4318') | | -| | `--telemetry-service-name` | Sets the value of the service.name resource attribute for telemetry data. | `toolbox` | +| Flag (Short) | Flag (Long) | Description | Default | +|--------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| `-a` | `--address` | Address of the interface the server will listen on. | `127.0.0.1` | +| | `--disable-reload` | Disables dynamic reloading of tools file. | | +| `-h` | `--help` | help for toolbox | | +| | `--log-level` | Specify the minimum level logged. Allowed: 'DEBUG', 'INFO', 'WARN', 'ERROR'. | `info` | +| | `--logging-format` | Specify logging format to use. Allowed: 'standard' or 'JSON'. | `standard` | +| `-p` | `--port` | Port the server will listen on. | `5000` | +| | `--prebuilt` | Use a prebuilt tool configuration by source type. See [Prebuilt Tools Reference](prebuilt-tools.md) for allowed values. | | +| | `--stdio` | Listens via MCP STDIO instead of acting as a remote HTTP server. | | +| | `--telemetry-gcp` | Enable exporting directly to Google Cloud Monitoring. | | +| | `--telemetry-otlp` | Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. 'http://127.0.0.1:4318') | | +| | `--telemetry-service-name` | Sets the value of the service.name resource attribute for telemetry data. | `toolbox` | | | `--tools-file` | File path specifying the tool configuration. Cannot be used with --tools-files or --tools-folder. | | | | `--tools-files` | Multiple file paths specifying tool configurations. Files will be merged. Cannot be used with --tools-file or --tools-folder. | | | | `--tools-folder` | Directory path containing YAML tool configuration files. All .yaml and .yml files in the directory will be loaded and merged. Cannot be used with --tools-file or --tools-files. | | -| | `--ui` | Launches the Toolbox UI web server. | | -| | `--allowed-origins` | Specifies a list of origins permitted to access this server. | `*` | -| `-v` | `--version` | version for toolbox | | +| | `--ui` | Launches the Toolbox UI web server. | | +| | `--allowed-origins` | Specifies a list of origins permitted to access this server for CORs access. | `*` | +| | `--allowed-hosts` | Specifies a list of hosts permitted to access this server to prevent DNS rebinding attacks. | `*` | +| `-v` | `--version` | version for toolbox | | ## Examples
internal/server/config.go+2 −0 modified@@ -68,6 +68,8 @@ type ServerConfig struct { UI bool // Specifies a list of origins permitted to access this server. AllowedOrigins []string + // Specifies a list of hosts permitted to access this server + AllowedHosts []string } type logFormat string
internal/server/server.go+25 −1 modified@@ -300,6 +300,21 @@ func InitializeConfigs(ctx context.Context, cfg ServerConfig) ( return sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, toolsetsMap, promptsMap, promptsetsMap, nil } +func hostCheck(allowedHosts map[string]struct{}) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, hasWildcard := allowedHosts["*"] + _, hostIsAllowed := allowedHosts[r.Host] + if !hasWildcard && !hostIsAllowed { + // Return 400 Bad Request or 403 Forbidden to block the attack + http.Error(w, "Invalid Host header", http.StatusBadRequest) + return + } + next.ServeHTTP(w, r) + }) + } +} + // NewServer returns a Server object based on provided Config. func NewServer(ctx context.Context, cfg ServerConfig) (*Server, error) { instrumentation, err := util.InstrumentationFromContext(ctx) @@ -374,7 +389,7 @@ func NewServer(ctx context.Context, cfg ServerConfig) (*Server, error) { // cors if slices.Contains(cfg.AllowedOrigins, "*") { - s.logger.WarnContext(ctx, "wildcard (`*`) allows all origin to access the resource and is not secure. Use it with cautious for public, non-sensitive data, or during local development. Recommended to use `--allowed-origins` flag to prevent DNS rebinding attacks") + s.logger.WarnContext(ctx, "wildcard (`*`) allows all origin to access the resource and is not secure. Use it with cautious for public, non-sensitive data, or during local development. Recommended to use `--allowed-origins` flag") } corsOpts := cors.Options{ AllowedOrigins: cfg.AllowedOrigins, @@ -385,6 +400,15 @@ func NewServer(ctx context.Context, cfg ServerConfig) (*Server, error) { MaxAge: 300, // cache preflight results for 5 minutes } r.Use(cors.Handler(corsOpts)) + // validate hosts for DNS rebinding attacks + if slices.Contains(cfg.AllowedHosts, "*") { + s.logger.WarnContext(ctx, "wildcard (`*`) allows all hosts to access the resource and is not secure. Use it with cautious for public, non-sensitive data, or during local development. Recommended to use `--allowed-hosts` flag to prevent DNS rebinding attacks") + } + allowedHostsMap := make(map[string]struct{}, len(cfg.AllowedHosts)) + for _, h := range cfg.AllowedHosts { + allowedHostsMap[h] = struct{}{} + } + r.Use(hostCheck(allowedHostsMap)) // control plane apiR, err := apiRouter(s)
internal/server/server_test.go+4 −3 modified@@ -43,9 +43,10 @@ func TestServe(t *testing.T) { addr, port := "127.0.0.1", 5000 cfg := server.ServerConfig{ - Version: "0.0.0", - Address: addr, - Port: port, + Version: "0.0.0", + Address: addr, + Port: port, + AllowedHosts: []string{"*"}, } otelShutdown, err := telemetry.SetupOTel(ctx, "0.0.0", "", false, "toolbox")
Vulnerability mechanics
Root cause
"The MCP Toolbox server did not validate the HTTP Host header, allowing DNS rebinding attacks to bypass CORS-only protections."
Attack vector
An attacker who can induce a victim to visit a malicious website or view a malicious ad can exploit DNS rebinding to bypass the browser's same-origin policy. The attacker registers a domain that initially resolves to a public IP but later resolves to `127.0.0.1` (or another local address). When the victim's browser makes a request to that domain, the request is forwarded to the locally running MCP Toolbox server. Because the server did not validate the `Host` header prior to v0.25.0, the attacker gains full control over the MCP server, enabling database manipulation, data theft, or arbitrary HTTP requests from the victim's machine [ref_id=2]. The patch notes that the previously added `--allowed-origins` (CORS) check was insufficient to prevent this attack [ref_id=1].
Affected code
The vulnerability exists in the `internal/server/server.go` file, specifically in the `NewServer` function where the server previously only validated the `Origin` header via CORS (`--allowed-origins`) but did not validate the `Host` header. The `cmd/root.go` file registers the new `--allowed-hosts` flag, and `internal/server/config.go` defines the `AllowedHosts` field in `ServerConfig`. The patch also updates documentation in `docs/en/how-to/deploy_toolbox.md`, `docs/en/how-to/deploy_docker.md`, and `docs/en/how-to/deploy_gke.md` to recommend using `--allowed-hosts` for DNS rebinding protection.
What the fix does
The patch introduces a new `--allowed-hosts` flag and a corresponding `hostCheck` middleware in `internal/server/server.go` [patch_id=5813447]. The middleware extracts the `Host` header from each incoming HTTP request and compares it against the configured allow list. If the host is not in the list and the list does not contain a wildcard (`*`), the server responds with `400 Bad Request` and the message "Invalid Host header". A startup warning is logged when either `--allowed-origins` or `--allowed-hosts` is set to `*`, alerting administrators to the insecure default. Documentation across deployment guides is updated to recommend using `--allowed-hosts` instead of `--allowed-origins` for DNS rebinding protection [patch_id=5813447].
Preconditions
- configThe MCP Toolbox server must be running with the default configuration (no `--allowed-hosts` restriction, i.e., `*`).
- inputThe victim must visit a malicious website or view a malicious ad controlled by the attacker.
- networkThe attacker must control a DNS domain that can be rebound from a public IP to a local address (e.g., 127.0.0.1).
Generated on Jun 13, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.