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

Regression with CVE-2023-0842 fix #672

Closed
guimard opened this issue Apr 25, 2023 · 6 comments
Closed

Regression with CVE-2023-0842 fix #672

guimard opened this issue Apr 25, 2023 · 6 comments

Comments

@guimard
Copy link

guimard commented Apr 25, 2023

Hi,

replacing {} by Object.create(null) does not produce the same value. This causes regression at least for node-rest-client tests (some Uncaught TypeError: Cannot read properties of undefined...). You should use Object.create({}) to have exactly the same behavior than previously:

$ node -p -e 'Object.create(null)'
[Object: null prototype] {}
$ node -p -e 'Object.create({})'
{}
@Leonidas-from-XIV
Copy link
Owner

But the whole point was not to do the same and fix the CVE. Does Object.create({}) fix the CVE without breaking backwards compatibility?

@guimard
Copy link
Author

guimard commented Apr 25, 2023

You're right @Leonidas-from-XIV, it doesn't fix the issue because you worked around the prototype pollution by setting prototype to "null" instead of filtering forbidden keys like __proto__

@guimard
Copy link
Author

guimard commented Apr 25, 2023

A workaround :

--- a/src/parser.coffee
+++ b/src/parser.coffee
@@ -181,8 +181,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
+            if key != '__proto__'
             objClone[key] = obj[key]
           s[@options.childkey].push objClone
           delete obj["#name"]
@@ -198,8 +199,11 @@ class exports.Parser extends events
         if @options.explicitRoot
           # avoid circular references
           old = obj
-          obj = Object.create(null)
-          obj[nodeName] = old
+          obj = {}
+          if nodeName === '__proto__'
+            console.error 'Node name __proto__ forbibben'
+          else
+            obj[nodeName] = old
 
         @resultObject = obj
         # parsing has ended, mark that so we won't throw exceptions from

@markwhitfeld
Copy link
Contributor

markwhitfeld commented Apr 26, 2023

Potentially a better fix would be to check the default javascript prototype for the property.
We could check using this code:

  if (!Object.prototype.hasOwnProperty(key)) //.... then parse the property

@markwhitfeld
Copy link
Contributor

markwhitfeld commented Apr 26, 2023

Ah, I understand the issue now.
Ignore my last suggestion, unless you are in fact interested in blocking all the default prototype properties.

The CVE is demonstrated through this:

// simulated exploit
({}).__proto__.foo = 1;
({})['constructor'].prototype.bar = 2;
// now any javascript object will contain these properties and values!
console.log({}.foo); // outputs 1
console.log({}.bar); // outputs 2

The best solution is to explicitly block __proto__ and constructor.
I don't think it is necessary to block prototype because that is only destructive through access via constructor.

@Leonidas-from-XIV
Copy link
Owner

I've released 0.6.0 which filters the dangerous fields and recommend everyone to use 0.6.2, which should fix the CVE while not breaking things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants