Skip to content

Commit 3b17e3c

Browse files
authored
fix(@angular/ssr): validate decoded x-forwarded-prefix before prefix checks
1 parent 1a8376b commit 3b17e3c

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

packages/angular/ssr/src/utils/validation.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,18 @@ function validateHeaders(request: Request): void {
268268
}
269269

270270
const xForwardedPrefix = getFirstHeaderValue(headers.get('x-forwarded-prefix'));
271-
if (xForwardedPrefix && INVALID_PREFIX_REGEX.test(xForwardedPrefix)) {
272-
throw new Error(
273-
'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.',
274-
);
271+
if (xForwardedPrefix) {
272+
let decodedXForwardedPrefix: string;
273+
try {
274+
decodedXForwardedPrefix = decodeURIComponent(xForwardedPrefix);
275+
} catch {
276+
throw new Error('Header "x-forwarded-prefix" contains an invalid percent-encoded sequence.');
277+
}
278+
279+
if (INVALID_PREFIX_REGEX.test(decodedXForwardedPrefix)) {
280+
throw new Error(
281+
'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.',
282+
);
283+
}
275284
}
276285
}

packages/angular/ssr/test/utils/validation_spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,36 @@ describe('Validation Utils', () => {
213213
.not.toThrow();
214214
}
215215
});
216+
217+
it('should throw error if x-forwarded-prefix contains percent-encoded invalid prefixes', () => {
218+
const inputs = ['%5Cevil.com', '%2F%2Fevil.com', '%2F..%2Fevil.com'];
219+
220+
for (const prefix of inputs) {
221+
const request = new Request('https://example.com', {
222+
headers: {
223+
'x-forwarded-prefix': prefix,
224+
},
225+
});
226+
227+
expect(() => validateRequest(request, allowedHosts, false))
228+
.withContext(`Prefix: "${prefix}"`)
229+
.toThrowError(
230+
'Header "x-forwarded-prefix" must not start with "\\" or multiple "/" or contain ".", ".." path segments.',
231+
);
232+
}
233+
});
234+
235+
it('should throw error if x-forwarded-prefix contains malformed percent-encoding', () => {
236+
const request = new Request('https://example.com', {
237+
headers: {
238+
'x-forwarded-prefix': '/%ZZ',
239+
},
240+
});
241+
242+
expect(() => validateRequest(request, allowedHosts, false)).toThrowError(
243+
'Header "x-forwarded-prefix" contains an invalid percent-encoded sequence.',
244+
);
245+
});
216246
});
217247

218248
describe('cloneRequestAndPatchHeaders', () => {

0 commit comments

Comments
 (0)