Repository navigation
Disable __proto__ #31951
Description
Activity
- addedsecurityIssues and PRs related to security.Issues and PRs related to security.
on Feb 25, 2020 cc @nodejs/tsc @nodejs/security @nodejs/v8
Reacted by Liran Tal and ErikFrom a security / dev perspective, there really is no reason not to disable the getter/setter for
__proro__on Object. If this is done in a major breaking release, modules that use it can easily move to better ways of manipulating the prototype.The core issue here is that even the most security-aware developers still get caught not thinking about it when using external inputs. It's impossible to completely seal internal logic from some external input coming in that contains
__proto__directly or after some string manipulation.I am seriously considering deleting the getter/setter when hapi loads and being done with it, letting any other non-hapi module that requires it to fail and get people to fix it. But this would be much better dealt with for everyone at the node core level (or v8). It's just a getter/setter on the Object prototype.
Reacted by Benjamin Flesch, Fabian, Yahor Siarheyenka, Denys Otrishko, devin ivy, Kirill Groshkov, Samuel Joli and ErikThere are two parts to
__proto__:Object.prototype.__proto__- Object literals with
__proto__
The second one is extremely popular for creating object literals with a null prototype, so I doubt we could disable it. I don't think the
Object.prototype.__proto__has anywhere near as much usage, but I would guess it is still a lot more than we could deal with.Reacted by Ben Noordhuis, Jordan Harband, Luigi Pinca, Anna Henningsen, Tuan Anh Tran, Denys Otrishko, ExE Boss, Celmaun and ErikI'm not convinced there's anything reasonable we can do at the Node.js level here by default without causing massive backwards compat issues. I wouldn't be opposed to running an experiment tho so see if that's wrong.
Reacted by snek, Jordan Harband, Denys Otrishko and ErikIt's part of JS; I don't think node dot JS should ever be in the position of disabling parts of the language, even with a flag.
(also most of these vulnerabilities are due to doing dangerous things with unsanitized user input, which is a bad practice that causes problems with or without
__proto__)Reacted by Erik and Jimmy WärtingReacted by Alyx, Shyam Chen, Edrich Hans Chua and UpsideDownFoxxoDrive-by comment:
I don't know if this is fixable / manageable on our side
For the vulnerabilities listed, which are about the setter on
Object.prototype, I think it would be straightforward for Node to just delete that setter during startup when the flag was set. (Possibly it would be a little more complicated to propagate that behavior to new contexts; I lack the relevant knowledge of the internals.)Object.defineProperty(Object.prototype, '__proto__', { set: void 0 });
Reacted by Jordan Harband, Anna Henningsen, John Murowaniecki, ExE Boss and ErikIMO there isn't anything node can/should do about this. Developers just need to implement better patterns. The typical scenario I've seen that relates to this kind of issue is people using
{}as a data storage mechanism instead of aMaporObject.create(null), both of which have been available for quite some time now and are more suitable for storing arbitrary data.Additionally, I'm not entirely sure why someone would be attempting the kind of operation in the OP (
'string' + nullProtoObj). Outside of edge cases like that, objects with null prototypes work just fine, even when callingJSON.stringify():> JSON.stringify({ foo: Object.create(null) }) '{"foo":{}}'Reacted by Jordan Harband, ExE Boss and ErikFor context, here is a real life RCE in Kibana using prototype pollution: https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
I know we have
--frozen-intrinsicsand--experimental-policies, perhaps we could make a more cohesive single set of defaults instead of a flag for each. This would be similar to the difficulty TypeScript faces with all its flags, andstrictmode for TS opts into the desired but breaking defaults.I recently looked into the feasibility of doing a
delete Object.prototype.__proto__for my serverside projects. It can work, but it is definitely still in use. This was evidenced when I tried to benchmark if it caused any changes in performance, and the benchmark tool failed.It's part of JS; I don't think node dot JS should ever be in the position of disabling parts of the language, even with a flag.
It's not really, though. At least, as it is currently specced in the optional for non-browsers section.
There are two parts to
__proto__:Object.prototype.__proto__- Object literals with
__proto__
The second one is extremely popular for creating object literals with a null prototype, so I doubt we could disable it. I don't think the
Object.prototype.__proto__has anywhere near as much usage, but I would guess it is still a lot more than we could deal with.The second form could still be valid, and is not a security concern, as you can't accidentally get user input into a literal.
Reacted by devin ivy, Linus Unnebäck and ErikNote that the specific JSON issue quoted in the issue is blocked when enabling the
--frozen-intrinsicsflag, as it is not possible to write to any builtin__proto__properties with this.Edit: it's just
--frozen-intrinsicsIt's part of JS; I don't think node dot JS should ever be in the position of disabling parts of the language, even with a flag.
(also most of these vulnerabilities are due to doing dangerous things with unsanitized user input, which is a bad practice that causes problems with or without
__proto__)It's not part of JS.
__proto__is defined in section B and Node.JS is not a browser so it's safe even__proto__is not implemented🤔When the ECMAScript host is a web browser the following additional properties of the standard built-in objects are defined. (section B)
The
--frozen-intrinsicsflag doesn't really work. It does prevent the more serious issue, where the global prototype is modified. It does not prevent changing an existing object prototype through assignment to theobj.__proto__property itself.In practice, most of Annex B is not really optional if you want to write or use portable code, but yes, that would be the loophole that would allow node to remove it, using the method described upthread.
24 remaining items
- added a commit that references this issue
on Mar 18, 2020 - added 2 commits that reference this issue
on Mar 19, 2020 - added 2 commits that reference this issue
on Apr 25, 2020 What is the state of this in v15.5.1 Current. As I understand the setter has been disabled ?
@GrosSacASac it is enabled by default but can be disabled via CLI flag
I believe babel/babel#12693 should fix the babel side, that was the last part in babel codebase that generated
__proto__-first code afaik.Since what version ? I could not find it in the changelogs ?
@GrosSacASac If you are speaking about Babel fix — that PR I linked is not merged yet.
That is, that PR only affects
loose: trueclass transforms.
Without loose mode, Babel was already fine since babel/babel#7675 (which was landed in v7.0.0) afaik.Sorry, I was asking about Node
--disable-protowas added in v13.12.0 and backported to v12.17.0: https://nodejs.org/dist/latest-v15.x/docs/api/cli.html#cli_disable_proto_modeReacted by Austin Wright, Gary Crye, Linus Unnebäck, Erik and Doug CoburnReacted by Daniel CousensBabel v7.12.13 should be fine even in loose mode.
Outside of loose mode, anything from v7.0.0 onwards appears to fine afaik.
There have been quite a few CVE related to
__proto__in the last while. I think it would be good to have a flag to enable/disable it.A quick example:
(It's not strictly related to JSON, as it can also apply to multipart data or other serialization format).
Some vulnerabilities:
I don't know if this is fixable / manageable on our side (vs V8), but
__proto__still causes significant vulnerabilities.Note that there are some modules to help with this, including https://github.com/hapijs/bourne.