diff --git a/packages/angular/ssr/src/utils/validation.ts b/packages/angular/ssr/src/utils/validation.ts index cb1bf6ecb56b..363930dec907 100644 --- a/packages/angular/ssr/src/utils/validation.ts +++ b/packages/angular/ssr/src/utils/validation.ts @@ -268,9 +268,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); + } 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 d8c3eaeebdb3..ba973b5951ef 100644 --- a/packages/angular/ssr/test/utils/validation_spec.ts +++ b/packages/angular/ssr/test/utils/validation_spec.ts @@ -147,8 +147,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', { @@ -213,6 +222,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, false)).toThrowError( + 'Header "x-forwarded-prefix" contains an invalid value and cannot be decoded.', + ); + }); }); describe('cloneRequestAndPatchHeaders', () => {