From 1238d614e1599fefadd4614ee4b5797a087f50ac Mon Sep 17 00:00:00 2001 From: Ethan <49207751+Et43@users.noreply.github.com> Date: Mon, 13 May 2024 20:57:17 +0200 Subject: [PATCH] Merge pull request from GHSA-xjcj-p2qv-q3rf * Update render.js # Improved handling of mustache expressions and v-pre attribute assignment ## Changes Made: - Ensured that the parent tag of such text nodes is explicitly set to a `

` tag with the `v-pre` attribute. - Added debug messages for better understanding of the script execution flow [THIS SHOULD REMOVED WHEN PUSHING TO PRODUCTION]. ## Why it Works: - When a mustache expression is found, the script either wraps it in a new `

` tag with the `v-pre` attribute or adds the `v-pre` attribute to the existing parent `

` tag. - This approach ensures that the template code is not removed but encapsulated within `

` tags with the `v-pre` attribute, as required. ## Test Cases Passed: 1. `{{ constructor.constructor('alert(1)')() }}` 2. `{{ constructor.constructor('alert(1)')() }}` 3. `

{{ constructor.constructor('alert(1)')() }}

` 4. `

{{ constructor.constructor('alert(1)')() }}

` 5. `

<xyz>{{constructor.constructor('alert("Test Case 8")')()}}<xyz>{{constructor.constructor('alert("Test Case 9")')()}}</xyz>

` This commit enhances the robustness and reliability of handling mustache expressions and ensures proper assignment of the `v-pre` attribute, to ensure that there is no room for the weaponization of the template code later in the rendering process. * fix: move template expressions after dom-purify + handle text nodes without parent --------- Co-authored-by: NGPixel --- .../modules/rendering/html-core/renderer.js | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/server/modules/rendering/html-core/renderer.js b/server/modules/rendering/html-core/renderer.js index f0ffbec8..a6426089 100644 --- a/server/modules/rendering/html-core/renderer.js +++ b/server/modules/rendering/html-core/renderer.js @@ -10,7 +10,7 @@ const mustacheRegExp = /(\{|{?){2}(.+?)(\}|}?){2}/i module.exports = { async render() { - const $ = cheerio.load(this.input, { + let $ = cheerio.load(this.input, { decodeEntities: true }) @@ -253,17 +253,35 @@ module.exports = { } }) + // -------------------------------- + // STEP: POST + // -------------------------------- + + let output = decodeEscape($.html('body').replace('', '').replace('', '')) + + for (let child of _.sortBy(_.filter(this.children, ['step', 'post']), ['order'])) { + const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`) + output = await renderer.init(output, child.config) + } + // -------------------------------- // Escape mustache expresions // -------------------------------- + $ = cheerio.load(output, { + decodeEntities: true + }) + function iterateMustacheNode (node) { - const list = $(node).contents().toArray() - list.forEach(item => { + $(node).contents().each((idx, item) => { if (item && item.type === 'text') { const rawText = $(item).text().replace(/\r?\n|\r/g, '') if (mustacheRegExp.test(rawText)) { - $(item).parent().attr('v-pre', true) + if (!item.parent || item.parent.name === 'body') { + $(item).wrap($('

').attr('v-pre', true)) + } else { + $(item).parent().attr('v-pre', true) + } } } else { iterateMustacheNode(item) @@ -276,18 +294,7 @@ module.exports = { $(elm).attr('v-pre', true) }) - // -------------------------------- - // STEP: POST - // -------------------------------- - - let output = decodeEscape($.html('body').replace('', '').replace('', '')) - - for (let child of _.sortBy(_.filter(this.children, ['step', 'post']), ['order'])) { - const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`) - output = await renderer.init(output, child.config) - } - - return output + return decodeEscape($.html('body').replace('', '').replace('', '')) } }