← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-9739 · CWE-942 · Disclosed 2026-05-27

Vulnerable to DNS rebinding attacks when using SSE

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a side door left cracked open on a service that was supposed to check badges at the front

CVE-2026-9739 is a DNS rebinding / CORS policy bypass in Google MCP Toolbox for Databases when the server is used over HTTP+SSE under MCP spec v2024-11-05. The SSE initialization handler kept a hardcoded Access-Control-Allow-Origin: *, which neutered the product's own --allowed-origins protection and let a malicious website talk to a victim's Toolbox instance through the browser. The fix landed in v1.2.0; based on release history, the vulnerable window is at least pre-1.2.0 builds using SSE, with beta-era builds likely included.

The scary part is what the Toolbox can reach: databases, cloud data sources, and whatever tools the operator wired into it. But the vendor-style CRITICAL/9.4 framing overstates enterprise reality because exploitation is not a clean unauthenticated internet service hit. It requires a victim running Toolbox over SSE, a browser session, a malicious page, and a reachable local or internal HTTP endpoint. That's a meaningful chain of prerequisites, so this belongs in MEDIUM, not in your top emergency patch lane.

"Assessed at MEDIUM: real impact is browser-driven and niche, not an internet-scale unauth RCE."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Lure a user with Toolbox open

The attacker hosts a malicious web page using a custom JavaScript rebinding client plus an attacker-controlled DNS rebinding domain. The victim has to visit that page while running a vulnerable Toolbox instance that is reachable from the browser, typically on 127.0.0.1:5000 or an internal host/port. This is user-interaction-dependent by design.
Conditions required:
  • Victim browses to attacker-controlled content
  • Toolbox is running at the time of the visit
  • HTTP transport is in use rather than --stdio
Where this breaks in practice:
  • No browser visit, no exploit
  • A lot of enterprise MCP usage stays on local stdio rather than remote SSE
  • Default listen address is 127.0.0.1, which narrows reach to browser-mediated attacks instead of raw internet exploitation
Detection/coverage: Email/web gateway telemetry may catch the lure, but vuln scanners usually miss this step because it is user-driven rather than banner-driven.
STEP 02

Bypass origin policy on the SSE endpoint

The malicious page opens the Toolbox SSE endpoint using the browser because the vulnerable handler returns Access-Control-Allow-Origin: *. That defeats the admin's intended --allowed-origins restriction and gives the page a foothold into the MCP transport. In the issue report, the impact is described as enabling session hijack and arbitrary tool use on the victim's behalf.
Conditions required:
  • Affected build before v1.2.0
  • SSE path in use under MCP spec v2024-11-05
  • Browser can reach the Toolbox host and port
Where this breaks in practice:
  • If the instance uses --stdio, this path disappears
  • If the service is patched to v1.2.0+, the hardcoded wildcard is removed
  • Host validation and strict origin controls reduce reach even before patching
Detection/coverage: Version-only detection is weak here; you need config/runtime awareness to know whether SSE is exposed.
STEP 03

Rebind and ride the victim's session

With a DNS rebinding service and browser fetch/XHR logic, the attacker pivots the victim browser to the local or internal Toolbox listener and reuses the established session flow. The public issue explicitly calls out session ID hijacking and arbitrary tool execution as the practical result. This turns the browser into a proxy into the victim's trusted MCP context.
Conditions required:
  • Attacker controls DNS for the lure domain
  • Victim browser accepts the rebinding sequence
  • Toolbox session semantics are available through SSE
Where this breaks in practice:
  • Timing and browser behavior make this less reliable than straight socket exploitation
  • Enterprise browser isolation or hardened DNS controls can break the chain
  • Some deployments may require additional auth before useful tools can be called
Detection/coverage: Proxy logs and browser telemetry may show odd localhost/internal requests originating from a public site; generic CVE scanners will not.
STEP 04

Invoke data-access tools through Toolbox

Once the browser can speak to the vulnerable MCP service, the attacker can abuse the configured tool surface using MCP JSON-RPC calls. In a real deployment that may mean execute_sql, BigQuery access, or other database-backed actions defined in tools.yaml. Impact is therefore highly environment-specific: one dev box may expose a demo database; another may front production analytics.
Conditions required:
  • Useful tools are configured in Toolbox
  • Connected data sources are reachable with the victim's trust context
  • Authz inside the tools is weak enough to permit meaningful reads or actions
Where this breaks in practice:
  • Blast radius is limited to what that one Toolbox instance is configured to reach
  • Least-privilege DB identities materially reduce impact
  • Some deployments expose read-only tooling rather than write-capable operations
Detection/coverage: Database logs, cloud audit logs, and Toolbox request logs are more useful than network scanners for spotting actual abuse.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo public evidence of active exploitation surfaced in the reviewed sources, and the supplied intel says KEV: No.
Proof-of-concept availabilityNo standalone weaponized PoC repo found. The exploit primitive is effectively documented in issue #3053, which spells out session hijack and arbitrary tool use.
EPSS0.00018 per the supplied intel and mirrored by Tenable; that is extremely low and consistent with a niche, precondition-heavy chain.
KEV statusNot KEV-listed in the supplied intel. No public campaign reporting was found in reviewed references.
CVSS stateContrary to the prompt's baseline note, NVD now shows a Google CNA CVSS v4 of 9.4 CRITICAL with vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H (NVD). I think that score overweighted technical impact and underweighted deployment friction.
Affected versionsAuthoritative advisories do not publish a clean affected range. Best-supported read is pre-1.2.0 builds using the SSE transport under spec v2024-11-05; beta-era builds are explicitly implicated in the advisory text.
Fixed versionFixed in mcp-toolbox v1.2.0, where the release notes include Remove hardcoded * allowed origin for sse (releases, CHANGELOG).
Exposure and scanning contextThis specific CVE is hard to fingerprint remotely, but the broader exposure class is real: Censys reported 12,520 Internet-accessible MCP services across 8,758 IPs as of 2026-04-28, with 1,056 data-access services observed (Censys).
Default posture amplifierToolbox docs say --allowed-origins and --allowed-hosts default to *, and warn this is insecure for production. That matters because this bug specifically nullified the intended origin restriction on SSE (CLI docs, deployment docs).
Disclosure and reporterDisclosed 2026-05-27 via CVE/NVD. The security issue was opened by Deeven-Seru on 2026-04-14 and fixed by Yuan325 in PR #3054 merged 2026-04-16.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.9/10)

The decisive downward pressure is the attacker path requirement: this is a browser-mediated attack against a running Toolbox instance using a specific transport, not a clean unauthenticated service exploit you can spray across the internet. The impact can be serious on the wrong host, but the reachable population is narrow and the blast radius is usually bounded to one developer workstation or one explicitly exposed MCP service.

HIGH Root cause and fixed version (`v1.2.0`)
MEDIUM Affected-version floor before `v1.2.0` because the advisory does not publish a full range
HIGH Severity downgrade from internet-RCE-style scoring to real-world enterprise risk

Why this verdict

  • Browser-required chain: exploitation needs a victim to visit attacker content while Toolbox is running and reachable from the browser; that is materially narrower than a raw unauthenticated network bug.
  • Transport-specific exposure: this only hits the SSE/HTTP path under MCP spec v2024-11-05; --stdio users and non-SSE flows are outside the blast radius.
  • Population limiter: MCP Toolbox is not a universal enterprise agent. Even among adopters, only a subset expose remote HTTP listeners with sensitive backends attached, so the vulnerable population is much smaller than the vendor-style score implies.

Why not higher?

I am not calling this HIGH or CRITICAL because the attacker does not simply point a socket at an exposed daemon and win. They need user interaction, a compatible browser path, a running vulnerable instance, and the right transport mode. Those are compounding friction points that sharply reduce exploit scale in real fleets.

Why not lower?

I am not dropping it to LOW because when the chain works, the attacker can pivot through a trusted MCP bridge into real data systems. On developer endpoints or analyst jump boxes with broad DB access, the confidentiality impact can be substantial even if the exploit path is finicky.

05 · Compensating Control

What to do — in priority order.

  1. Prefer --stdio where possible — Move local IDE and agent workflows off remote HTTP/SSE and onto stdio where the protocol design allows it. That removes the browser-reachable attack surface entirely; for a MEDIUM finding there is no mitigation SLA, so do this during normal architecture hardening rather than as an emergency change.
  2. Lock down --allowed-hosts and --allowed-origins — Set explicit hostnames and frontend origins instead of *, and verify they survive startup wrappers, containers, and service definitions. Even though this bug bypassed origin checks on the vulnerable SSE path, strict host validation still cuts off common rebinding routes; there is no mitigation SLA, so apply in the next normal change window.
  3. Keep Toolbox on loopback unless there is a real reason not to — The CLI default listen address is 127.0.0.1; keep it there for workstation use and avoid 0.0.0.0 unless you intentionally need shared access. That sharply shrinks the exposed population; for MEDIUM, treat this as routine hardening with no mitigation SLA.
  4. Reduce backend privileges behind Toolbox — The real damage comes from what the configured tools can reach, so use read-only DB identities where practical and split privileged write paths away from developer-facing MCP servers. This limits blast radius even if the browser pivot succeeds; again, no mitigation SLA applies.
What doesn't work
  • Simply setting --allowed-origins on a vulnerable build does not solve the SSE path, because the issue exists specifically because that policy was overridden by a hardcoded wildcard header.
  • Relying on 'it's only localhost' is not enough; the product's own CLI docs warn that wildcard host settings are unsafe even for local use because browsers can be tricked into talking to loopback services.
  • Version-only network scanning is weak here. You also need to know whether the instance is actually using the vulnerable HTTP/SSE path.
06 · Verification

Crowdsourced verification payload.

Run this on the target host or developer workstation where toolbox is installed. Invoke it as python3 check_cve_2026_9739.py --binary /usr/local/bin/toolbox --config /path/to/tools.yaml; no admin rights are required unless your config files are unreadable to the current user. It checks the local Toolbox version and, if you provide config files, looks for obvious SSE transport markers before returning VULNERABLE, PATCHED, or UNKNOWN.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# check_cve_2026_9739.py
# Detect likely exposure to CVE-2026-9739 in Google MCP Toolbox for Databases.
# Exit codes:
#   0 = PATCHED
#   1 = VULNERABLE
#   2 = UNKNOWN

import argparse
import os
import re
import shutil
import subprocess
import sys
from typing import Optional, Tuple

PATCHED_VERSION = (1, 2, 0)
VERSION_RE = re.compile(r'(\d+)\.(\d+)\.(\d+)')
SSE_PATTERNS = [
    re.compile(r'\bsse\b', re.IGNORECASE),
    re.compile(r'/mcp\b', re.IGNORECASE),
    re.compile(r'event-stream', re.IGNORECASE),
]


def parse_version(text: str) -> Optional[Tuple[int, int, int]]:
    m = VERSION_RE.search(text or '')
    if not m:
        return None
    return tuple(int(x) for x in m.groups())


def version_str(v: Tuple[int, int, int]) -> str:
    return '.'.join(str(x) for x in v)


def run_version(binary: str) -> Tuple[Optional[Tuple[int, int, int]], str]:
    cmds = [
        [binary, '--version'],
        [binary, '-v'],
        [binary, 'version'],
    ]
    output = ''
    for cmd in cmds:
        try:
            proc = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            output = (proc.stdout or '') + '\n' + (proc.stderr or '')
            v = parse_version(output)
            if v:
                return v, output.strip()
        except Exception:
            continue
    return None, output.strip()


def file_contains_sse(path: str) -> Optional[bool]:
    try:
        with open(path, 'r', encoding='utf-8', errors='ignore') as fh:
            data = fh.read()
    except Exception:
        return None

    for pat in SSE_PATTERNS:
        if pat.search(data):
            return True
    return False


def main() -> int:
    parser = argparse.ArgumentParser(description='Check likely exposure to CVE-2026-9739')
    parser.add_argument('--binary', default='toolbox', help='Path to toolbox binary (default: toolbox in PATH)')
    parser.add_argument('--config', action='append', default=[], help='Optional config file(s) to inspect for SSE usage')
    args = parser.parse_args()

    binary = args.binary
    if os.path.sep not in binary:
        resolved = shutil.which(binary)
        if resolved:
            binary = resolved

    if not os.path.exists(binary):
        print('UNKNOWN - toolbox binary not found: {}'.format(args.binary))
        return 2

    version, raw = run_version(binary)
    if not version:
        print('UNKNOWN - unable to determine toolbox version from: {}'.format(raw or 'no output'))
        return 2

    if version >= PATCHED_VERSION:
        print('PATCHED - toolbox {} is >= {}'.format(version_str(version), version_str(PATCHED_VERSION)))
        return 0

    # Pre-1.2.0 is potentially affected, but the CVE is specific to SSE transport.
    if not args.config:
        print('UNKNOWN - toolbox {} is < {}, but SSE usage was not checked (supply --config)'.format(
            version_str(version), version_str(PATCHED_VERSION)
        ))
        return 2

    saw_readable = False
    sse_hit = False
    unreadable = []
    clean = []

    for cfg in args.config:
        result = file_contains_sse(cfg)
        if result is None:
            unreadable.append(cfg)
            continue
        saw_readable = True
        if result:
            sse_hit = True
        else:
            clean.append(cfg)

    if sse_hit:
        print('VULNERABLE - toolbox {} is < {} and at least one config appears to reference SSE'.format(
            version_str(version), version_str(PATCHED_VERSION)
        ))
        return 1

    if saw_readable:
        print('UNKNOWN - toolbox {} is < {}, but provided config(s) did not show obvious SSE markers'.format(
            version_str(version), version_str(PATCHED_VERSION)
        ))
        return 2

    print('UNKNOWN - toolbox {} is < {}, but config files were unreadable: {}'.format(
        version_str(version), version_str(PATCHED_VERSION), ', '.join(unreadable) if unreadable else 'none'
    ))
    return 2


if __name__ == '__main__':
    sys.exit(main())
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: find every mcp-toolbox instance below 1.2.0 and separate stdio-only usage from HTTP/SSE-reachable usage. For this MEDIUM call there is noisgate mitigation SLA: no mitigation SLA — go straight to the 365-day remediation window; still, use the next normal change window to lock down --allowed-hosts, --allowed-origins, and loopback-only binding on any browser-reachable instances. Then patch remaining vulnerable installs to v1.2.0 or later within the noisgate remediation SLA of ≤365 days, with developer workstations and any intentionally exposed MCP services first in line.

Sources

  1. NVD CVE-2026-9739
  2. GitHub Advisory GHSA-7pf3-8xx7-rvhf
  3. Security issue #3053
  4. Fix PR #3054
  5. MCP Toolbox release notes
  6. MCP Toolbox changelog
  7. MCP Toolbox CLI hardening docs
  8. Censys MCP exposure research
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.