diff --git a/src/agents/mcp-sse.test.ts b/src/agents/mcp-sse.test.ts index 567ad04b785..3aabce1663a 100644 --- a/src/agents/mcp-sse.test.ts +++ b/src/agents/mcp-sse.test.ts @@ -94,6 +94,30 @@ describe("resolveSseMcpServerLaunchConfig", () => { } }); + it("redacts sensitive query params in invalid URL errors", () => { + const result = resolveSseMcpServerLaunchConfig({ + url: "mcp.example.com/sse?token=secret123&api_key=key456", + }); + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.reason).toContain("token=***"); + expect(result.reason).toContain("api_key=***"); + expect(result.reason).not.toContain("secret123"); + expect(result.reason).not.toContain("key456"); + } + }); + + it("redacts embedded credentials in invalid URL errors", () => { + const result = resolveSseMcpServerLaunchConfig({ + url: "//user:pass@mcp.example.com/sse", + }); + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.reason).toContain("***:***@"); + expect(result.reason).not.toContain("user:pass"); + } + }); + it("rejects non-http protocols", () => { const result = resolveSseMcpServerLaunchConfig({ url: "ftp://example.com/sse" }); expect(result.ok).toBe(false); diff --git a/src/agents/mcp-sse.ts b/src/agents/mcp-sse.ts index fa903fcf909..a3ef82706ee 100644 --- a/src/agents/mcp-sse.ts +++ b/src/agents/mcp-sse.ts @@ -51,8 +51,13 @@ export function resolveSseMcpServerLaunchConfig( try { parsed = new URL(url); } catch { - // Redact potential credentials from the invalid URL before including in reason. - const redactedUrl = url.replace(/\/\/([^@]+)@/, "//***:***@"); + // Redact potential credentials and sensitive query params from the invalid URL. + const redactedUrl = url + .replace(/\/\/([^@]+)@/, "//***:***@") + .replace( + /([?&])(token|key|api_key|apikey|secret|access_token|password|pass|auth|client_secret|refresh_token)=([^&]*)/gi, + "$1$2=***", + ); return { ok: false, reason: `its url is not a valid URL: ${redactedUrl}` }; } if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {