fix(cspNonce): don't overwrite existing nonce values (#16415)

This commit is contained in:
Adam Hines 2024-04-18 01:24:26 -06:00 committed by GitHub
parent 6cccef78a5
commit b8726357c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 9 deletions

View File

@ -1180,24 +1180,29 @@ export function injectNonceAttributeTagHook(
return
}
const { nodeName, attrs, sourceCodeLocation } = node
if (
node.nodeName === 'script' ||
(node.nodeName === 'link' &&
node.attrs.some(
nodeName === 'script' ||
(nodeName === 'link' &&
attrs.some(
(attr) =>
attr.name === 'rel' &&
parseRelAttr(attr.value).some((a) => processRelType.has(a)),
))
) {
// If we already have a nonce attribute, we don't need to add another one
if (attrs.some(({ name }) => name === 'nonce')) {
return
}
const startTagEndOffset = sourceCodeLocation!.startTag!.endOffset
// if the closing of the start tag includes a `/`, the offset should be 2 so the nonce
// is appended prior to the `/`
const appendOffset =
html[node.sourceCodeLocation!.startTag!.endOffset - 2] === '/' ? 2 : 1
const appendOffset = html[startTagEndOffset - 2] === '/' ? 2 : 1
s.appendRight(
node.sourceCodeLocation!.startTag!.endOffset - appendOffset,
` nonce="${nonce}"`,
)
s.appendRight(startTagEndOffset - appendOffset, ` nonce="${nonce}"`)
}
})

View File

@ -27,6 +27,20 @@ test('dynamic js', async () => {
)
})
test('inline js', async () => {
await expectWithRetry(() => page.textContent('.inline-js')).toBe(
'inline-js: ok',
)
})
test('nonce attributes are not repeated', async () => {
const htmlSource = await page.content()
expect(htmlSource).not.toContain(/nonce=""[^>]*nonce=""/)
await expectWithRetry(() => page.textContent('.double-nonce-js')).toBe(
'double-nonce-js: ok',
)
})
test('meta[property=csp-nonce] is injected', async () => {
const meta = await page.$('meta[property=csp-nonce]')
expect(await (await meta.getProperty('nonce')).jsonValue()).not.toBe('')

View File

@ -11,3 +11,13 @@
<p class="dynamic">dynamic</p>
<p class="js">js: error</p>
<p class="dynamic-js">dynamic-js: error</p>
<p class="inline-js">inline-js: error</p>
<p class="double-nonce-js">double-nonce-js: error</p>
<script>
document.querySelector('.inline-js').textContent = 'inline-js: ok'
</script>
<script nonce="#$NONCE$#">
// this test case is to ensure that the nonce isn't being
// double-applied if an existing attribute is present.
document.querySelector('.double-nonce-js').textContent = 'double-nonce-js: ok'
</script>