diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aa7b7ef68..04fb6b3a8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: echo "EOF" >> $GITHUB_OUTPUT - name: Create the release if: steps.changelog.outputs.changelog_content != '' - uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 with: name: ${{ github.ref_name }} body: '${{ steps.changelog.outputs.changelog_content }}' diff --git a/CHANGELOG.md b/CHANGELOG.md index a7abcd6f8..aee09ae08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). +## 8.5.10 + +- Fixed XSS via unescaped `` in non-bundler cases (by @TharVid). + ## 8.5.9 - Speed up source map encoding paring in case of the error. diff --git a/lib/lazy-result.js b/lib/lazy-result.js index 1ea52b87a..085ff228a 100644 --- a/lib/lazy-result.js +++ b/lib/lazy-result.js @@ -281,6 +281,13 @@ class LazyResult { } } this.hasListener = Object.keys(this.listeners).length > 0 + this.hasKeyListeners = false + for (let key in this.listeners) { + if (key.includes('-')) { + this.hasKeyListeners = true + break + } + } } async runAsync() { @@ -517,19 +524,51 @@ class LazyResult { walkSync(node) { node[isClean] = true - let events = getEvents(node) - for (let event of events) { - if (event === CHILDREN) { - if (node.nodes) { - node.each(child => { - if (!child[isClean]) this.walkSync(child) - }) - } - } else { - let visitors = this.listeners[event] - if (visitors) { - if (this.visitSync(visitors, node.toProxy())) return - } + let type = TYPE_TO_CLASS_NAME[node.type] + let listeners = this.listeners + let proxy + let visitors + let key + + if (this.hasKeyListeners) { + if (node.type === 'decl') { + key = node.prop.toLowerCase() + } else if (node.type === 'atrule') { + key = node.name.toLowerCase() + } + } + + visitors = listeners[type] + if (visitors) { + proxy = node.toProxy() + if (this.visitSync(visitors, proxy)) return + } + + if (key) { + visitors = listeners[type + '-' + key] + if (visitors) { + if (!proxy) proxy = node.toProxy() + if (this.visitSync(visitors, proxy)) return + } + } + + if (node.nodes) { + node.each(child => { + if (!child[isClean]) this.walkSync(child) + }) + } + + visitors = listeners[type + 'Exit'] + if (visitors) { + if (!proxy) proxy = node.toProxy() + if (this.visitSync(visitors, proxy)) return + } + + if (key) { + visitors = listeners[type + 'Exit-' + key] + if (visitors) { + if (!proxy) proxy = node.toProxy() + this.visitSync(visitors, proxy) } } } diff --git a/lib/processor.js b/lib/processor.js index 2afe2ef0a..5eda6c410 100644 --- a/lib/processor.js +++ b/lib/processor.js @@ -7,7 +7,7 @@ let Root = require('./root') class Processor { constructor(plugins = []) { - this.version = '8.5.9' + this.version = '8.5.10' this.plugins = this.normalize(plugins) } diff --git a/lib/stringifier.js b/lib/stringifier.js index e07ad12e7..012fa622d 100644 --- a/lib/stringifier.js +++ b/lib/stringifier.js @@ -1,5 +1,17 @@ 'use strict' +// Escapes sequences that could break out of an HTML { + let root = new Root() + root.append(new Rule({ selector: '' })) + root.append(new AtRule({ name: 'media', params: '