diff --git a/src/security/external-content.test.ts b/src/security/external-content.test.ts index 3e22bb34c4a..6bbe5e65d86 100644 --- a/src/security/external-content.test.ts +++ b/src/security/external-content.test.ts @@ -246,6 +246,12 @@ describe("external-content security", () => { expect(isExternalHookSession("hook:custom:456")).toBe(true); }); + it("identifies mixed-case hook prefixes", () => { + expect(isExternalHookSession("HOOK:gmail:msg-123")).toBe(true); + expect(isExternalHookSession("Hook:custom:456")).toBe(true); + expect(isExternalHookSession(" HOOK:webhook:123 ")).toBe(true); + }); + it("rejects non-hook sessions", () => { expect(isExternalHookSession("cron:daily-task")).toBe(false); expect(isExternalHookSession("agent:main")).toBe(false); @@ -266,6 +272,12 @@ describe("external-content security", () => { expect(getHookType("hook:custom:456")).toBe("webhook"); }); + it("returns hook type for mixed-case hook prefixes", () => { + expect(getHookType("HOOK:gmail:msg-123")).toBe("email"); + expect(getHookType(" HOOK:webhook:123 ")).toBe("webhook"); + expect(getHookType("Hook:custom:456")).toBe("webhook"); + }); + it("returns unknown for non-hook sessions", () => { expect(getHookType("cron:daily")).toBe("unknown"); }); diff --git a/src/security/external-content.ts b/src/security/external-content.ts index 49629db9aef..e1fd9335d7d 100644 --- a/src/security/external-content.ts +++ b/src/security/external-content.ts @@ -286,10 +286,11 @@ export function buildSafeExternalPrompt(params: { * Checks if a session key indicates an external hook source. */ export function isExternalHookSession(sessionKey: string): boolean { + const normalized = sessionKey.trim().toLowerCase(); return ( - sessionKey.startsWith("hook:gmail:") || - sessionKey.startsWith("hook:webhook:") || - sessionKey.startsWith("hook:") // Generic hook prefix + normalized.startsWith("hook:gmail:") || + normalized.startsWith("hook:webhook:") || + normalized.startsWith("hook:") // Generic hook prefix ); } @@ -297,13 +298,14 @@ export function isExternalHookSession(sessionKey: string): boolean { * Extracts the hook type from a session key. */ export function getHookType(sessionKey: string): ExternalContentSource { - if (sessionKey.startsWith("hook:gmail:")) { + const normalized = sessionKey.trim().toLowerCase(); + if (normalized.startsWith("hook:gmail:")) { return "email"; } - if (sessionKey.startsWith("hook:webhook:")) { + if (normalized.startsWith("hook:webhook:")) { return "webhook"; } - if (sessionKey.startsWith("hook:")) { + if (normalized.startsWith("hook:")) { return "webhook"; } return "unknown";