You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Static review of public source at commit 603217008710. No traffic was sent to any MCP environment.
createMcpExpressApp (and the matching Hono helper) auto-arm Host + Origin validation only for loopback hosts. Binding to 0.0.0.0 / :: logs a warning, but any other non-loopback host (LAN IP, container hostname, public DNS name) gets neither middleware nor that warning:
packages/middleware/express/src/express.ts (same ladder in packages/middleware/hono/src/hono.ts):
constlocalhostHosts=['127.0.0.1','localhost','::1'];if(localhostHosts.includes(host)){app.use(localhostHostValidation());}elseif(host==='0.0.0.0'||host==='::'){console.warn(`Warning: Server is binding to ${host} without DNS rebinding protection. `+'Consider using the allowedHosts option...');}// Origin: only armed for loopback or explicit allowedOrigins
So createMcpExpressApp({ host: '192.168.1.10' }) or { host: 'mcp.internal' } serves without Host/Origin checks and without the operator nudge that 0.0.0.0 already gets. DNS rebinding / browser-origin abuse is exactly what those middleware exist for on HTTP MCP endpoints.
Suggested change:
Treat every non-loopback host like 0.0.0.0: require allowedHosts (and ideally allowedOrigins), or at least emit the same warning.
Or fail closed: refuse to construct the app for non-loopback binds unless allowlists are provided.
Keep the explicit opt-out path for demos that truly need an open bind.
Severity: medium as insecure default / defense-in-depth for non-loopback HTTP mounts; not claiming a working exploit against a specific deployment. No proof-of-concept.
Happy to send a focused PR if this direction is useful.
Any host that is neither loopback nor 0.0.0.0/:: falls through both branches, so there's no Host check and no warning. Equivalent wildcard spellings like 0:0:0:0:0:0:0:0 or [::] also skip the warning.
A backwards-compatible fix I'd suggest: make the warning branch the else (any non-loopback bind without allowedHosts warns), and apply it the same way in all three factories, with one test per factory. Fail-closed would break existing LAN/container deployments that sit behind their own auth or proxy, so I think it belongs in a separate, explicitly breaking change if you want it at all.
This also overlaps with #2852, which proposes removing the default Origin arming from the same code. It's probably worth settling both in one place so the Host/Origin defaults don't get changed twice.
@tiagovilasboas, you offered a PR. If you're not planning to send one, I'm happy to put up the warning-only version for all three factories once a maintainer confirms that direction.
The same ladder is in the published v1.x line. createMcpExpressApp in @modelcontextprotocol/sdk 1.30.1, released the day after this was filed, installs no Host validation for a host outside the three loopback names when allowedHosts is unset, and only warns for 0.0.0.0 and ::. 1.30.1 also added a comment above the parser saying a disallowed Host is answered 403 unread, which on those binds has nothing to run after. A fix on main would need a v1.x backport, the way #2698 got #2717.
Activity
iamhuman-cheolheelee commentedon Sep 24, 2026
Confirmed on
main(7f7a94c). The same ladder exists in all three factories, not just Express/Hono:packages/middleware/express/src/express.ts(createMcpExpressApp)packages/middleware/hono/src/hono.ts:92-98packages/middleware/fastify/src/fastify.ts:81-86(usesapp.log.warn)Any
hostthat is neither loopback nor0.0.0.0/::falls through both branches, so there's no Host check and no warning. Equivalent wildcard spellings like0:0:0:0:0:0:0:0or[::]also skip the warning.A backwards-compatible fix I'd suggest: make the warning branch the
else(any non-loopback bind withoutallowedHostswarns), and apply it the same way in all three factories, with one test per factory. Fail-closed would break existing LAN/container deployments that sit behind their own auth or proxy, so I think it belongs in a separate, explicitly breaking change if you want it at all.This also overlaps with #2852, which proposes removing the default Origin arming from the same code. It's probably worth settling both in one place so the Host/Origin defaults don't get changed twice.
@tiagovilasboas, you offered a PR. If you're not planning to send one, I'm happy to put up the warning-only version for all three factories once a maintainer confirms that direction.
imran-siddique commentedon Sep 25, 2026
The same ladder is in the published v1.x line.
createMcpExpressAppin@modelcontextprotocol/sdk1.30.1, released the day after this was filed, installs no Host validation for a host outside the three loopback names whenallowedHostsis unset, and only warns for0.0.0.0and::. 1.30.1 also added a comment above the parser saying a disallowed Host is answered 403 unread, which on those binds has nothing to run after. A fix on main would need a v1.x backport, the way #2698 got #2717.