VYPR
High severityOSV Advisory· Published Sep 8, 2025· Updated Apr 15, 2026

CVE-2025-58444

CVE-2025-58444

Description

The MCP inspector is a developer tool for testing and debugging MCP servers. A cross-site scripting issue was reported in versions of the MCP Inspector local development tool prior to 0.16.6 when connecting to untrusted remote MCP servers with a malicious redirect URI. This could be leveraged to interact directly with the inspector proxy to trigger arbitrary command execution. Users are advised to update to 0.16.6 to resolve this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@modelcontextprotocol/inspectornpm
< 0.16.60.16.6

Affected products

1

Patches

2
377211061b51

Merge pull request #777 from cliffhall/bump-version-to-0.16.6

5 files changed · +15 15
  • client/package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "@modelcontextprotocol/inspector-client",
    -  "version": "0.16.5",
    +  "version": "0.16.6",
       "description": "Client-side application for the Model Context Protocol inspector",
       "license": "MIT",
       "author": "Anthropic, PBC (https://anthropic.com)",
    
  • cli/package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "@modelcontextprotocol/inspector-cli",
    -  "version": "0.16.5",
    +  "version": "0.16.6",
       "description": "CLI for the Model Context Protocol inspector",
       "license": "MIT",
       "author": "Anthropic, PBC (https://anthropic.com)",
    
  • package.json+4 4 modified
    @@ -1,6 +1,6 @@
     {
       "name": "@modelcontextprotocol/inspector",
    -  "version": "0.16.5",
    +  "version": "0.16.6",
       "description": "Model Context Protocol inspector",
       "license": "MIT",
       "author": "Anthropic, PBC (https://anthropic.com)",
    @@ -47,9 +47,9 @@
         "check-version": "node scripts/check-version-consistency.js"
       },
       "dependencies": {
    -    "@modelcontextprotocol/inspector-cli": "^0.16.5",
    -    "@modelcontextprotocol/inspector-client": "^0.16.5",
    -    "@modelcontextprotocol/inspector-server": "^0.16.5",
    +    "@modelcontextprotocol/inspector-cli": "^0.16.6",
    +    "@modelcontextprotocol/inspector-client": "^0.16.6",
    +    "@modelcontextprotocol/inspector-server": "^0.16.6",
         "@modelcontextprotocol/sdk": "^1.17.5",
         "concurrently": "^9.2.0",
         "open": "^10.2.0",
    
  • package-lock.json+8 8 modified
    @@ -1,22 +1,22 @@
     {
       "name": "@modelcontextprotocol/inspector",
    -  "version": "0.16.5",
    +  "version": "0.16.6",
       "lockfileVersion": 3,
       "requires": true,
       "packages": {
         "": {
           "name": "@modelcontextprotocol/inspector",
    -      "version": "0.16.5",
    +      "version": "0.16.6",
           "license": "MIT",
           "workspaces": [
             "client",
             "server",
             "cli"
           ],
           "dependencies": {
    -        "@modelcontextprotocol/inspector-cli": "^0.16.5",
    -        "@modelcontextprotocol/inspector-client": "^0.16.5",
    -        "@modelcontextprotocol/inspector-server": "^0.16.5",
    +        "@modelcontextprotocol/inspector-cli": "^0.16.6",
    +        "@modelcontextprotocol/inspector-client": "^0.16.6",
    +        "@modelcontextprotocol/inspector-server": "^0.16.6",
             "@modelcontextprotocol/sdk": "^1.17.5",
             "concurrently": "^9.2.0",
             "open": "^10.2.0",
    @@ -46,7 +46,7 @@
         },
         "cli": {
           "name": "@modelcontextprotocol/inspector-cli",
    -      "version": "0.16.5",
    +      "version": "0.16.6",
           "license": "MIT",
           "dependencies": {
             "@modelcontextprotocol/sdk": "^1.17.5",
    @@ -69,7 +69,7 @@
         },
         "client": {
           "name": "@modelcontextprotocol/inspector-client",
    -      "version": "0.16.5",
    +      "version": "0.16.6",
           "license": "MIT",
           "dependencies": {
             "@modelcontextprotocol/sdk": "^1.17.5",
    @@ -11746,7 +11746,7 @@
         },
         "server": {
           "name": "@modelcontextprotocol/inspector-server",
    -      "version": "0.16.5",
    +      "version": "0.16.6",
           "license": "MIT",
           "dependencies": {
             "@modelcontextprotocol/sdk": "^1.17.5",
    
  • server/package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "@modelcontextprotocol/inspector-server",
    -  "version": "0.16.5",
    +  "version": "0.16.6",
       "description": "Server-side application for the Model Context Protocol inspector",
       "license": "MIT",
       "author": "Anthropic, PBC (https://anthropic.com)",
    
650f3090d263

fix: add validation for OAuth redirect URLs

5 files changed · +197 12
  • client/src/components/AuthDebugger.tsx+17 0 modified
    @@ -6,6 +6,7 @@ import { AuthDebuggerState, EMPTY_DEBUGGER_STATE } from "../lib/auth-types";
     import { OAuthFlowProgress } from "./OAuthFlowProgress";
     import { OAuthStateMachine } from "../lib/oauth-state-machine";
     import { SESSION_KEYS } from "../lib/constants";
    +import { validateRedirectUrl } from "@/utils/urlValidation";
     
     export interface AuthDebuggerProps {
       serverUrl: string;
    @@ -163,6 +164,22 @@ const AuthDebugger = ({
               currentState.oauthStep === "authorization_code" &&
               currentState.authorizationUrl
             ) {
    +          // Validate the URL before redirecting
    +          try {
    +            validateRedirectUrl(currentState.authorizationUrl);
    +          } catch (error) {
    +            updateAuthState({
    +              ...currentState,
    +              isInitiatingAuth: false,
    +              latestError: error instanceof Error ? error : new Error(String(error)),
    +              statusMessage: {
    +                type: "error",
    +                message: `Invalid authorization URL: ${error instanceof Error ? error.message : String(error)}`,
    +              },
    +            });
    +            return;
    +          }
    +          
               // Store the current auth state before redirecting
               sessionStorage.setItem(
                 SESSION_KEYS.AUTH_DEBUGGER_STATE,
    
  • client/src/components/OAuthFlowProgress.tsx+29 6 modified
    @@ -4,6 +4,8 @@ import { Button } from "./ui/button";
     import { DebugInspectorOAuthClientProvider } from "@/lib/auth";
     import { useEffect, useMemo, useState } from "react";
     import { OAuthClientInformation } from "@modelcontextprotocol/sdk/shared/auth.js";
    +import { validateRedirectUrl } from "@/utils/urlValidation";
    +import { useToast } from "@/lib/hooks/useToast";
     
     interface OAuthStepProps {
       label: string;
    @@ -71,6 +73,7 @@ export const OAuthFlowProgress = ({
       updateAuthState,
       proceedToNextStep,
     }: OAuthFlowProgressProps) => {
    +  const { toast } = useToast();
       const provider = useMemo(
         () => new DebugInspectorOAuthClientProvider(serverUrl),
         [serverUrl],
    @@ -239,16 +242,25 @@ export const OAuthFlowProgress = ({
                     <p className="text-xs break-all">
                       {authState.authorizationUrl}
                     </p>
    -                <a
    -                  href={authState.authorizationUrl}
    -                  target="_blank"
    -                  rel="noopener noreferrer"
    +                <button
    +                  onClick={() => {
    +                    try {
    +                      validateRedirectUrl(authState.authorizationUrl!);
    +                      window.open(authState.authorizationUrl!, "_blank");
    +                    } catch (error) {
    +                      toast({
    +                        title: "Invalid URL",
    +                        description: error instanceof Error ? error.message : "The authorization URL is not valid",
    +                        variant: "destructive",
    +                      });
    +                    }
    +                  }}
                       className="flex items-center text-blue-500 hover:text-blue-700"
                       aria-label="Open authorization URL in new tab"
                       title="Open authorization URL"
                     >
                       <ExternalLink className="h-4 w-4" />
    -                </a>
    +                </button>
                   </div>
                   <p className="text-xs text-muted-foreground mt-2">
                     Click the link to authorize in your browser. After
    @@ -354,7 +366,18 @@ export const OAuthFlowProgress = ({
               authState.authorizationUrl && (
                 <Button
                   variant="outline"
    -              onClick={() => window.open(authState.authorizationUrl!, "_blank")}
    +              onClick={() => {
    +                try {
    +                  validateRedirectUrl(authState.authorizationUrl!);
    +                  window.open(authState.authorizationUrl!, "_blank");
    +                } catch (error) {
    +                  toast({
    +                    title: "Invalid URL",
    +                    description: error instanceof Error ? error.message : "The authorization URL is not valid",
    +                    variant: "destructive",
    +                  });
    +                }
    +              }}
                 >
                   Open in New Tab
                 </Button>
    
  • client/src/lib/auth.ts+3 6 modified
    @@ -11,6 +11,7 @@ import {
     import { discoverAuthorizationServerMetadata } from "@modelcontextprotocol/sdk/client/auth.js";
     import { SESSION_KEYS, getServerSpecificKey } from "./constants";
     import { generateOAuthState } from "@/utils/oauthUtils";
    +import { validateRedirectUrl } from "@/utils/urlValidation";
     
     /**
      * Discovers OAuth scopes from server metadata, with preference for resource metadata scopes
    @@ -182,12 +183,8 @@ export class InspectorOAuthClientProvider implements OAuthClientProvider {
       }
     
       redirectToAuthorization(authorizationUrl: URL) {
    -    if (
    -      authorizationUrl.protocol !== "http:" &&
    -      authorizationUrl.protocol !== "https:"
    -    ) {
    -      throw new Error("Authorization URL must be HTTP or HTTPS");
    -    }
    +    // Validate the URL using the shared utility
    +    validateRedirectUrl(authorizationUrl.href);
         window.location.href = authorizationUrl.href;
       }
     
    
  • client/src/utils/__tests__/urlValidation.test.ts+127 0 added
    @@ -0,0 +1,127 @@
    +import { validateRedirectUrl } from "../urlValidation";
    +
    +describe("validateRedirectUrl", () => {
    +  describe("valid URLs", () => {
    +    it("should allow HTTP URLs", () => {
    +      expect(() => validateRedirectUrl("http://example.com")).not.toThrow();
    +    });
    +
    +    it("should allow HTTPS URLs", () => {
    +      expect(() => validateRedirectUrl("https://example.com")).not.toThrow();
    +    });
    +
    +    it("should allow URLs with ports", () => {
    +      expect(() => validateRedirectUrl("https://example.com:8080")).not.toThrow();
    +    });
    +
    +    it("should allow URLs with paths", () => {
    +      expect(() => validateRedirectUrl("https://example.com/path/to/auth")).not.toThrow();
    +    });
    +
    +    it("should allow URLs with query parameters", () => {
    +      expect(() => validateRedirectUrl("https://example.com?param=value")).not.toThrow();
    +    });
    +  });
    +
    +  describe("invalid URLs - XSS vectors", () => {
    +    it("should block javascript: protocol", () => {
    +      expect(() => validateRedirectUrl("javascript:alert('XSS')")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +
    +    it("should block javascript: with encoded characters", () => {
    +      expect(() => validateRedirectUrl("javascript:alert%28%27XSS%27%29")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +
    +    it("should block data: protocol", () => {
    +      expect(() => validateRedirectUrl("data:text/html,<script>alert('XSS')</script>")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +
    +    it("should block vbscript: protocol", () => {
    +      expect(() => validateRedirectUrl("vbscript:msgbox")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +
    +    it("should block file: protocol", () => {
    +      expect(() => validateRedirectUrl("file:///etc/passwd")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +
    +    it("should block about: protocol", () => {
    +      expect(() => validateRedirectUrl("about:blank")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +
    +    it("should block custom protocols", () => {
    +      expect(() => validateRedirectUrl("custom://example")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +  });
    +
    +  describe("edge cases", () => {
    +    it("should handle malformed URLs", () => {
    +      expect(() => validateRedirectUrl("not a url")).toThrow(
    +        "Invalid URL: not a url"
    +      );
    +    });
    +
    +    it("should handle empty string", () => {
    +      expect(() => validateRedirectUrl("")).toThrow(
    +        "Invalid URL: "
    +      );
    +    });
    +
    +    it("should handle URLs with unicode characters", () => {
    +      expect(() => validateRedirectUrl("https://例え.jp")).not.toThrow();
    +    });
    +
    +    it("should handle URLs with case variations", () => {
    +      expect(() => validateRedirectUrl("HTTPS://EXAMPLE.COM")).not.toThrow();
    +      expect(() => validateRedirectUrl("HtTpS://example.com")).not.toThrow();
    +    });
    +
    +    it("should handle protocol-relative URLs as invalid", () => {
    +      expect(() => validateRedirectUrl("//example.com")).toThrow(
    +        "Invalid URL: //example.com"
    +      );
    +    });
    +
    +    it("should handle URLs with authentication", () => {
    +      expect(() => validateRedirectUrl("https://user:pass@example.com")).not.toThrow();
    +    });
    +  });
    +
    +  describe("security considerations", () => {
    +    it("should not be fooled by whitespace", () => {
    +      expect(() => validateRedirectUrl(" javascript:alert('XSS')")).toThrow();
    +      expect(() => validateRedirectUrl("javascript:alert('XSS') ")).toThrow();
    +    });
    +
    +    it("should handle null bytes", () => {
    +      expect(() => validateRedirectUrl("java\x00script:alert('XSS')")).toThrow();
    +    });
    +
    +    it("should handle tab characters", () => {
    +      expect(() => validateRedirectUrl("java\tscript:alert('XSS')")).toThrow();
    +    });
    +
    +    it("should handle newlines", () => {
    +      expect(() => validateRedirectUrl("java\nscript:alert('XSS')")).toThrow();
    +    });
    +
    +    it("should handle mixed case protocols", () => {
    +      expect(() => validateRedirectUrl("JaVaScRiPt:alert('XSS')")).toThrow(
    +        "Authorization URL must be HTTP or HTTPS"
    +      );
    +    });
    +  });
    +});
    \ No newline at end of file
    
  • client/src/utils/urlValidation.ts+21 0 added
    @@ -0,0 +1,21 @@
    +/**
    + * Validates that a URL is safe for redirection.
    + * Only allows HTTP and HTTPS protocols to prevent XSS attacks.
    + * 
    + * @param url - The URL string to validate
    + * @throws Error if the URL has an unsafe protocol
    + */
    +export function validateRedirectUrl(url: string): void {
    +  try {
    +    const parsedUrl = new URL(url);
    +    if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
    +      throw new Error("Authorization URL must be HTTP or HTTPS");
    +    }
    +  } catch (error) {
    +    if (error instanceof Error && error.message === "Authorization URL must be HTTP or HTTPS") {
    +      throw error;
    +    }
    +    // If URL parsing fails, it's also invalid
    +    throw new Error(`Invalid URL: ${url}`);
    +  }
    +}
    \ No newline at end of file
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.