The Browser Changed the Address: DBHub DNS Rebinding to SQL
The first request failed exactly as expected: 403 Forbidden. The browser claimed attacker.example as its origin while the target identified itself as localhost:8080. DBHub saw the mismatch and closed the door.
Then one detail changed. Not the JavaScript. Not the MCP method. Not the database query. Only the Host header. When both Origin and Host said dbhub-rebind.example, DBHub 0.22.4 returned its tool inventory and executed a harmless SQL canary in my loopback lab. Version 0.22.5 rejected the same request shape.
That small difference captures CVE-2026-61742: an attacker-controlled website could use DNS rebinding to drive an unauthenticated DBHub HTTP transport from a victim’s browser, without prompt injection, model output, or a compromised MCP client.[1]
The check that looked reasonable
DBHub exposes database operations as MCP tools. Its default transport is stdio, but HTTP mode is documented for clients that need a network endpoint. In affected releases through 0.22.4, the HTTP middleware tried to stop hostile browser origins by extracting the hostname from Origin, extracting the hostname from Host, and requiring equality.[1]
Host: dbhub-rebind.example:8080
Origin: http://dbhub-rebind.example
originHost === host // true
The comparison answers the wrong question. It proves that two request fields are self-consistent. It does not prove that either value belongs to a trusted deployment.
DNS rebinding exploits that distinction. The victim first resolves an attacker-owned hostname to the attacker’s web server and loads JavaScript. After the DNS answer changes, the same hostname resolves to a loopback or internal address reachable from the victim’s browser. The browser still sees the same origin tuple. The network destination has moved underneath it.

A browser-origin pivot, not an AI exploit
The attack chain matters because it bypasses the defenses teams usually associate with agent security:
- A victim visits an attacker-controlled hostname on the DBHub HTTP port.
- The page loads while DNS points to the public attacker server.
- The hostname is rebound to a victim-accessible DBHub address.
- Browser JavaScript sends JSON-RPC to
/mcp. BothHostandOriginretain the attacker hostname. - The vulnerable equality check passes and reflects that origin in
Access-Control-Allow-Origin. - The page invokes
tools/listortools/call, reads the response, and can return data through ordinary browser egress.
No LLM needs to interpret hostile content. No approval dialog needs to be fooled. This is a browser-to-service authorization failure in an MCP deployment. It complements the broader trust-boundary model in MCP Security: How to Secure Agents, Tools, and Servers, but the entry point is lower in the stack: HTTP authority and name resolution.
Operationally, the browser becomes a network deputy. It can reach loopback, a developer VLAN, a VPN route, or an internal subnet that the attacker cannot access directly. If DBHub holds a production DSN, the effective authority is determined by exposed tools and database credentials, not by the apparent locality of port 8080.
What the loopback lab proved
I reproduced the post-rebinding request shape on September 28, 2026, using the packaged demo database and loopback only. No external rebinding service was used. The harness selected ephemeral ports, launched each version, issued one mismatch control, then sent identical rebind-shaped tools/list and read-only execute_sql requests.
# Isolated lab target, not a third-party service
npx -y @bytebase/[email protected] \
--transport http --port "$PORT" --demo
# TCP destination stays 127.0.0.1; headers simulate the post-rebind shape
Host: dbhub-rebind.example:$PORT
Origin: http://dbhub-rebind.example
{"jsonrpc":"2.0","id":"read","method":"tools/call",
"params":{"name":"execute_sql",
"arguments":{"sql":"select 'LOCAL_LAB_CANARY' as proof"}}}
| Version | Mismatched Origin/Host | Rebind-shaped tools/list | SQL canary |
|---|---|---|---|
| 0.22.4 | 403 | 200 | 200, canary returned |
| 0.22.5 | 403 | 403 | 403 |
The result isolates the security decision. It does not simulate DNS timing, browser resolver behavior, or production routing. It demonstrates that once a browser produces the accepted post-rebinding headers, 0.22.4 dispatches MCP methods while 0.22.5 blocks them. That is the claim the lab can support, and no more.
The patch replaces consistency with policy
The fix merged in DBHub pull request 340 validates every Host against an allow-list, including requests that omit Origin. If Origin exists, it must also belong to the allowed set before it can be reflected.[2][3] Loopback names remain allowed. Operators can add reverse-proxy or deployment names through --allowed-hosts or DBHUB_ALLOWED_HOSTS.
This is a better security invariant: the server decides which names represent it. An attacker can make DNS and browser headers agree, but cannot add an arbitrary hostname to the server’s configured trust set.
Do not stop at 0.22.5. DBHub 0.22.6 also addresses a separate failure where readonly = true depended on a SQL classifier while the intended database-level enforcement was not wired into normal configuration. The advisory documents side-effecting SELECT functions and adds engine-level controls such as PostgreSQL BEGIN READ ONLY and SQLite PRAGMA query_only.[5][6] The combined lesson is familiar from MCP tools and permissions in practice: a tool label is not a database boundary.
Detection and defense
Patch first. Upgrade to 0.22.6 or later.[4] Bind HTTP transport to loopback when remote access is unnecessary. If a reverse proxy is required, authenticate there and keep an explicit DBHub host allow-list. Avoid the wildcard --allowed-hosts "*" unless an upstream control is genuinely enforcing both authentication and destination policy.[2]
Reduce database authority. Use a dedicated DSN with schema-level grants, statement timeouts, and no server-file, extension, or program-execution privileges. Read-only enforcement should exist in the database session, not only in an MCP tool definition or keyword parser. This also limits damage from prompt injection and compromised clients, attack paths explored in enterprise AI attack chains.
Hunt the boundary crossing. Useful signals are relational:
- HTTP requests to
/mcpwhoseHostis not an approved deployment name. - Browser-like
Origin,Sec-Fetch-Site, and user-agent headers reaching a service normally called by an MCP client. - Bursts of
tools/listfollowed bytools/callfrom an unexpected workstation or developer endpoint. - DNS answers for one hostname moving from a public address to loopback, RFC 1918, link-local, or another internal range within a short window.
- Database sessions from DBHub enumerating metadata and then issuing atypical queries or producing unusual result volume.
A single control will miss variants. Host allow-listing prevents the documented rebinding shape. Authentication protects the dispatch layer. Network binding narrows reachability. Database least privilege constrains impact. DNS, HTTP, MCP, and database telemetry together explain the sequence.
Strategic takeaway
MCP did not create DNS rebinding, but it raises the value of the service behind the browser boundary. A local endpoint may now hold a compact catalog of high-level operations backed by privileged credentials. That makes old web assumptions operationally expensive.
The detail to remember is not the hostname trick. It is the decision error. Equality between attacker-influenced values is not authorization. When an MCP server crosses from stdio to HTTP, treat host identity, client authentication, tool capability, and database authority as separate controls. If any one of them is expected to stand in for the others, the attack path is already forming.
Sources
- DBHub advisory for CVE-2026-61742, published September 24, 2026.
- DBHub pull request 340, Host allow-list fix and validation rationale.
- Fix commit 5bf5c32, merged June 24, 2026.
- DBHub v0.22.6 release, published July 10, 2026.
- DBHub read-only enforcement advisory, published September 24, 2026.
- DBHub pull request 342, engine-level read-only enforcement.
💜 Enjoyed this content? Support the blog with USDT (TRC20):
TX7obcjHQbDUXb4mGqoASEu1QFTKT2CFGG
