diff --git a/packages/angular/ssr/src/utils/validation.ts b/packages/angular/ssr/src/utils/validation.ts index 9e83e144b347..49b27428df1d 100644 --- a/packages/angular/ssr/src/utils/validation.ts +++ b/packages/angular/ssr/src/utils/validation.ts @@ -260,9 +260,21 @@ function validateHeaders(request: Request): void { } const xForwardedPrefix = getFirstHeaderValue(headers.get('x-forwarded-prefix')); - if (xForwardedPrefix && INVALID_PREFIX_REGEX.test(xForwardedPrefix)) { - throw new Error( - 'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.', - ); + if (xForwardedPrefix) { + let xForwardedPrefixDecoded: string; + try { + xForwardedPrefixDecoded = decodeURIComponent(xForwardedPrefix).trim(); + } catch (e) { + throw new Error( + 'Header "x-forwarded-prefix" contains an invalid value and cannot be decoded.', + { cause: e }, + ); + } + + if (INVALID_PREFIX_REGEX.test(xForwardedPrefixDecoded)) { + throw new Error( + 'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.', + ); + } } } diff --git a/packages/angular/ssr/test/utils/validation_spec.ts b/packages/angular/ssr/test/utils/validation_spec.ts index acf1e4829e8e..595ed397a751 100644 --- a/packages/angular/ssr/test/utils/validation_spec.ts +++ b/packages/angular/ssr/test/utils/validation_spec.ts @@ -125,8 +125,17 @@ describe('Validation Utils', () => { ); }); - it('should throw error if x-forwarded-prefix starts with a backslash or multiple slashes', () => { - const inputs = ['//evil', '\\\\evil', '/\\evil', '\\/evil', '\\evil']; + it('should throw error if x-forwarded-prefix starts with a backslash or multiple slashes including encoded', () => { + const inputs = [ + '//evil', + '\\\\evil', + '/\\evil', + '\\/evil', + '\\evil', + '%5Cevil', + '%2F%2Fevil', + '%2F..%2Fevil', + ]; for (const prefix of inputs) { const request = new Request('https://example.com', { @@ -191,6 +200,18 @@ describe('Validation Utils', () => { .not.toThrow(); } }); + + it('should throw error if x-forwarded-prefix contains malformed encoding', () => { + const request = new Request('https://example.com', { + headers: { + 'x-forwarded-prefix': '/%invalid', + }, + }); + + expect(() => validateRequest(request, allowedHosts)).toThrowError( + 'Header "x-forwarded-prefix" contains an invalid value and cannot be decoded.', + ); + }); }); describe('cloneRequestAndPatchHeaders', () => {