From 7894ae39f0fae1cf9c6b4ed8eee9b2d92512e253 Mon Sep 17 00:00:00 2001 From: joeltco Date: Tue, 9 Jun 2026 10:31:49 -0400 Subject: [PATCH] fix(front): reject backslash paths in isValidReturnToPath (open-redirect hardening) (#21287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `isValidReturnToPath` validates the post-login `returnTo` path and already rejects protocol-relative `//` paths — but not the backslash variant. Browsers normalize `\` to `/`, so `/\evil.com` resolves like `//evil.com` (a protocol-relative, external URL) while still passing the existing `//` check: ```ts isValidReturnToPath("/\\evil.com"); // returns true today; should be false ``` This hardens the open-redirect guard by rejecting any path containing a backslash, so a `returnTo` can only ever be a same-site absolute path. ## Changes - `isValidReturnToPath`: reject paths containing `\`. - Added tests for backslash-tricked paths. Framed as defense-in-depth — the validator should reject this class regardless of how each consumer performs the redirect. --------- Co-authored-by: Charles Bochet --- .../auth/utils/__tests__/isValidReturnToPath.test.ts | 6 ++++++ .../src/modules/auth/utils/isValidReturnToPath.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/auth/utils/__tests__/isValidReturnToPath.test.ts b/packages/twenty-front/src/modules/auth/utils/__tests__/isValidReturnToPath.test.ts index 54f84c12a8..fbc9f8e39b 100644 --- a/packages/twenty-front/src/modules/auth/utils/__tests__/isValidReturnToPath.test.ts +++ b/packages/twenty-front/src/modules/auth/utils/__tests__/isValidReturnToPath.test.ts @@ -17,6 +17,12 @@ describe('isValidReturnToPath', () => { expect(isValidReturnToPath('//evil.com')).toBe(false); }); + it('should return false for backslash-tricked paths', () => { + expect(isValidReturnToPath('/\\evil.com')).toBe(false); + expect(isValidReturnToPath('/\\/evil.com')).toBe(false); + expect(isValidReturnToPath('/objects\\..\\evil')).toBe(false); + }); + it('should return false for onboarding paths', () => { expect(isValidReturnToPath('/create/workspace')).toBe(false); expect(isValidReturnToPath('/create/profile')).toBe(false); diff --git a/packages/twenty-front/src/modules/auth/utils/isValidReturnToPath.ts b/packages/twenty-front/src/modules/auth/utils/isValidReturnToPath.ts index 67fa1db958..e3fadb322b 100644 --- a/packages/twenty-front/src/modules/auth/utils/isValidReturnToPath.ts +++ b/packages/twenty-front/src/modules/auth/utils/isValidReturnToPath.ts @@ -16,7 +16,7 @@ export const isValidReturnToPath = (path: string): boolean => { return false; } - if (!path.startsWith('/') || path.startsWith('//')) { + if (!path.startsWith('/') || path.startsWith('//') || path.includes('\\')) { return false; }