allow loopback to localhost on mcp, only for local MCP clients

This commit is contained in:
Amruth Pillai
2026-04-26 10:59:10 +02:00
parent 76e00ae019
commit 623ca5c675
63 changed files with 84 additions and 460 deletions
+10 -22
View File
@@ -2,9 +2,10 @@ import { createFileRoute } from "@tanstack/react-router";
import { auth } from "@/integrations/auth/config";
import { env } from "@/utils/env";
import { isPrivateOrLoopbackHost, parseAllowedHostList, parseUrl } from "@/utils/url-security";
import { isAllowedOAuthRedirectUri, parseAllowedHostList } from "@/utils/url-security";
const oauthDynamicClientRedirectHosts = parseAllowedHostList(env.OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS);
const oauthTrustedOrigins = [new URL(env.APP_URL).origin.toLowerCase()];
const oauthAuthorizeSanitizedParams = [
"prompt",
"redirect_uri",
@@ -17,25 +18,6 @@ const oauthAuthorizeSanitizedParams = [
"resource",
] as const;
function isAllowedDynamicClientRedirectUri(value: string) {
const parsed = parseUrl(value);
if (!parsed) return false;
if (parsed.protocol !== "https:") return false;
if (parsed.username || parsed.password) return false;
if (parsed.hash) return false;
if (isPrivateOrLoopbackHost(parsed.hostname)) return false;
const appOrigin = new URL(env.APP_URL).origin.toLowerCase();
const origin = parsed.origin.toLowerCase();
const hostname = parsed.hostname.toLowerCase();
if (origin === appOrigin) return true;
if (oauthDynamicClientRedirectHosts.has(origin)) return true;
if (oauthDynamicClientRedirectHosts.has(hostname)) return true;
return false;
}
function sanitizeOAuthAuthorizeRequest(request: Request): Request {
if (request.method !== "GET") return request;
@@ -117,8 +99,14 @@ async function validateDynamicClientRegistrationRequest(request: Request): Promi
const redirectUris = Array.isArray(body.redirect_uris) ? body.redirect_uris : [];
for (const redirectUri of redirectUris) {
if (typeof redirectUri !== "string" || !isAllowedDynamicClientRedirectUri(redirectUri)) {
return Response.json({ message: "redirect_uri is not allowed" }, { status: 400 });
if (
typeof redirectUri !== "string" ||
!isAllowedOAuthRedirectUri(redirectUri, oauthTrustedOrigins, oauthDynamicClientRedirectHosts)
) {
return Response.json(
{ error: "invalid_redirect_uri", error_description: "redirect_uri is not allowed" },
{ status: 400 },
);
}
}
}