🔣 fix: Escape SPA Language Attribute (#15248)

This commit is contained in:
Danny Avila 2026-08-26 07:37:36 -04:00 committed by GitHub
parent 6d8b1cb013
commit f34a49007d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 34 additions and 4 deletions

View file

@ -195,6 +195,14 @@ describe('Content Security Policy', () => {
expect(response.headers['content-security-policy']).toContain("script-src 'nonce-");
});
it('keeps replacement patterns in the language cookie as literal attribute text', async () => {
const response = await request(app).get('/').set('Cookie', 'lang=$&');
expect(response.status).toBe(200);
expect(response.text).toContain('<html lang="$&amp;">');
expect(response.text).not.toContain('<html lang="lang="en-US"">');
});
it('carries deployment-specific sources and the clickjacking default', async () => {
const csp = (await request(app).get('/')).headers['content-security-policy'];

View file

@ -19,6 +19,7 @@ const {
applyCspNonce,
createCspPolicy,
shellCacheHeaders,
escapeHtmlAttribute,
ErrorController,
QUERY_DEVTOOLS_HEADER,
createSecurityHeaders,
@ -434,8 +435,8 @@ if (cluster.isMaster) {
res.vary(QUERY_DEVTOOLS_HEADER);
const lang = req.cookies.lang || req.headers['accept-language']?.split(',')[0] || 'en-US';
const saneLang = lang.replace(/"/g, '&quot;');
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, `lang="${saneLang}"`);
const saneLang = escapeHtmlAttribute(lang);
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, () => `lang="${saneLang}"`);
updatedIndexHtml = maybeInjectQueryDevtoolsBootstrap(updatedIndexHtml, req);
/* Nonce last: every injected script above must be stamped too. */

View file

@ -20,6 +20,7 @@ const {
applyCspNonce,
createCspPolicy,
shellCacheHeaders,
escapeHtmlAttribute,
ErrorController,
memoryDiagnostics,
createSecurityHeaders,
@ -252,8 +253,8 @@ const startServer = async () => {
res.vary(QUERY_DEVTOOLS_HEADER);
const lang = req.cookies.lang || req.headers['accept-language']?.split(',')[0] || 'en-US';
const saneLang = lang.replace(/"/g, '&quot;');
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, `lang="${saneLang}"`);
const saneLang = escapeHtmlAttribute(lang);
let updatedIndexHtml = indexHTML.replace(/lang="en-US"/g, () => `lang="${saneLang}"`);
updatedIndexHtml = maybeInjectQueryDevtoolsBootstrap(updatedIndexHtml, req);
/* Nonce last: every injected script above must be stamped too. */