Skip to content

Commit

Permalink
Merge pull request from GHSA-xjcj-p2qv-q3rf
Browse files Browse the repository at this point in the history
* 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 `<p>` 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 `<p>` tag with the `v-pre` attribute or adds the `v-pre` attribute to the existing parent `<p>` tag.
- This approach ensures that the template code is not removed but encapsulated within `<p>` tags with the `v-pre` attribute, as required.

## Test Cases Passed:
1. `<xyz>{{ constructor.constructor('alert(1)')() }}</xyz>`
2. `<xyz>{{ constructor.constructor('alert(1)')() }}</xyz>`
3. `<p><xyz>{{ constructor.constructor('alert(1)')() }}</p>`
4. `<p><xyz>{{ constructor.constructor('alert(1)')() }}</xyz></p>`
5. `<p>&lt;xyz&gt;{{constructor.constructor('alert("Test Case 8")')()}}&lt;xyz&gt;{{constructor.constructor('alert("Test Case 9")')()}}&lt;/xyz&gt;</p>`

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 <github@ngpixel.com>
  • Loading branch information
Et43 and NGPixel authored May 13, 2024
1 parent 98c04fe commit 1238d61
Showing 1 changed file with 23 additions and 16 deletions.
39 changes: 23 additions & 16 deletions server/modules/rendering/html-core/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const mustacheRegExp = /(\{|&#x7b;?){2}(.+?)(\}|&#x7d;?){2}/i

module.exports = {
async render() {
const $ = cheerio.load(this.input, {
let $ = cheerio.load(this.input, {
decodeEntities: true
})

Expand Down Expand Up @@ -253,17 +253,35 @@ module.exports = {
}
})

// --------------------------------
// STEP: POST
// --------------------------------

let output = decodeEscape($.html('body').replace('<body>', '').replace('</body>', ''))

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($('<p>').attr('v-pre', true))
} else {
$(item).parent().attr('v-pre', true)
}
}
} else {
iterateMustacheNode(item)
Expand All @@ -276,18 +294,7 @@ module.exports = {
$(elm).attr('v-pre', true)
})

// --------------------------------
// STEP: POST
// --------------------------------

let output = decodeEscape($.html('body').replace('<body>', '').replace('</body>', ''))

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('<body>', '').replace('</body>', ''))
}
}

Expand Down

0 comments on commit 1238d61

Please sign in to comment.