fix(front): reject backslash paths in isValidReturnToPath (open-redirect hardening) (#21287)

## 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 <charles@twenty.com>
This commit is contained in:
joeltco
2026-06-09 10:31:49 -04:00
committed by GitHub
parent c5e95c6649
commit 7894ae39f0
2 changed files with 7 additions and 1 deletions
@@ -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);
@@ -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;
}