fix: Sanitize control characters in page parameter response headers (#10237)

This commit is contained in:
Manuel
2026-03-18 20:48:43 +00:00
committed by GitHub
parent c77c884771
commit 337ffd65cc
2 changed files with 51 additions and 14 deletions
+26
View File
@@ -1040,6 +1040,32 @@ describe('Pages Router', () => {
}).catch(e => e);
expect(response.status).not.toBe(500);
});
it('does not return 500 when page parameter contains CRLF characters', async () => {
await reconfigureServer(config);
const crlf = 'abc\r\nX-Injected: 1';
const url = `${config.publicServerURL}/apps/choose_password?appId=test&token=${encodeURIComponent(crlf)}&username=testuser`;
const response = await request({
url: url,
followRedirects: false,
}).catch(e => e);
expect(response.status).not.toBe(500);
expect(response.status).toBe(200);
});
it('does not return 500 when page parameter contains CRLF characters in redirect response', async () => {
await reconfigureServer(config);
const crlf = 'abc\r\nX-Injected: 1';
const url = `${config.publicServerURL}/apps/test/resend_verification_email`;
const response = await request({
method: 'POST',
url: url,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `username=${encodeURIComponent(crlf)}`,
followRedirects: false,
}).catch(e => e);
expect(response.status).not.toBe(500);
});
});
describe('custom route', () => {
+25 -14
View File
@@ -455,13 +455,7 @@ export class PagesRouter extends PromiseRouter {
// Add placeholders in header to allow parsing for programmatic use
// of response, instead of having to parse the HTML content.
const encode = this.pagesConfig.encodePageParamHeaders;
const headers = Object.entries(params).reduce((m, p) => {
if (p[1] !== undefined) {
m[`${pageParamHeaderPrefix}${p[0].toLowerCase()}`] = encode ? encodeURIComponent(p[1]) : p[1];
}
return m;
}, {});
const headers = this.composePageParamHeaders(params);
return { text: data, headers: headers };
}
@@ -555,6 +549,29 @@ export class PagesRouter extends PromiseRouter {
return locale;
}
/**
* Composes page parameter headers from the given parameters. Control
* characters are always stripped from header values to prevent
* ERR_INVALID_CHAR errors. Values are URI-encoded if the
* `encodePageParamHeaders` option is enabled.
* @param {Object} params The parameters to include in the headers.
* @returns {Object} The headers object.
*/
composePageParamHeaders(params) {
const encode = this.pagesConfig.encodePageParamHeaders;
return Object.entries(params).reduce((m, p) => {
if (p[1] !== undefined) {
let value = encode ? encodeURIComponent(p[1]) : p[1];
if (typeof value === 'string') {
// eslint-disable-next-line no-control-regex
value = value.replace(/[\x00-\x1f\x7f]/g, '');
}
m[`${pageParamHeaderPrefix}${p[0].toLowerCase()}`] = value;
}
return m;
}, {});
}
/**
* Creates a response with http redirect.
* @param {Object} req The express request.
@@ -578,13 +595,7 @@ export class PagesRouter extends PromiseRouter {
// Add parameters to header to allow parsing for programmatic use
// of response, instead of having to parse the HTML content.
const encode = this.pagesConfig.encodePageParamHeaders;
const headers = Object.entries(params).reduce((m, p) => {
if (p[1] !== undefined) {
m[`${pageParamHeaderPrefix}${p[0].toLowerCase()}`] = encode ? encodeURIComponent(p[1]) : p[1];
}
return m;
}, {});
const headers = this.composePageParamHeaders(params);
return {
status: 303,