Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved fix for CVE-2023-0842 #674

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/parser.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ defaults = require('./defaults').defaults
isEmpty = (thing) ->
return typeof thing is "object" && thing? && Object.keys(thing).length is 0

isValidKey = (key) ->
return key != '__proto__' && key != 'constructor' && key != 'prototype'

processItem = (processors, item, key) ->
item = process(item, key) for process in processors
return item
Expand Down Expand Up @@ -52,6 +55,7 @@ class exports.Parser extends events
@emit err

assignOrPush: (obj, key, newValue) =>
return if not isValidKey(key)
if key not of obj
if not @options.explicitArray
obj[key] = newValue
Expand Down Expand Up @@ -102,18 +106,19 @@ class exports.Parser extends events
charkey = @options.charkey

@saxParser.onopentag = (node) =>
obj = Object.create(null)
obj = {}
obj[charkey] = ""
unless @options.ignoreAttrs
for own key of node.attributes
if attrkey not of obj and not @options.mergeAttrs
obj[attrkey] = Object.create(null)
obj[attrkey] = {}
newValue = if @options.attrValueProcessors then processItem(@options.attrValueProcessors, node.attributes[key], key) else node.attributes[key]
processedKey = if @options.attrNameProcessors then processItem(@options.attrNameProcessors, key) else key
if @options.mergeAttrs
@assignOrPush obj, processedKey, newValue
else
obj[attrkey][processedKey] = newValue
if isValidKey(processedKey)
if @options.mergeAttrs
@assignOrPush obj, processedKey, newValue
else
obj[attrkey][processedKey] = newValue

# need a place to store the node name
obj["#name"] = if @options.tagNameProcessors then processItem(@options.tagNameProcessors, node.name) else node.name
Expand Down Expand Up @@ -163,7 +168,7 @@ class exports.Parser extends events
# put children into <childkey> property and unfold chars if necessary
if @options.explicitChildren and not @options.mergeAttrs and typeof obj is 'object'
if not @options.preserveChildrenOrder
node = Object.create(null)
node = {}
# separate attributes
if @options.attrkey of obj
node[@options.attrkey] = obj[@options.attrkey]
Expand All @@ -181,9 +186,9 @@ class exports.Parser extends events
# append current node onto parent's <childKey> array
s[@options.childkey] = s[@options.childkey] or []
# push a clone so that the node in the children array can receive the #name property while the original obj can do without it
objClone = Object.create(null)
objClone = {}
for own key of obj
objClone[key] = obj[key]
objClone[key] = obj[key] if isValidKey(key)
s[@options.childkey].push objClone
delete obj["#name"]
# re-check whether we can collapse the node now to just the charkey value
Expand All @@ -198,7 +203,7 @@ class exports.Parser extends events
if @options.explicitRoot
# avoid circular references
old = obj
obj = Object.create(null)
obj = {}
obj[nodeName] = old

@resultObject = obj
Expand Down