Uh oh!
There was an error while loading. Please reload this page.
process: set process.env prototype to null - #30063
Conversation
This removes all inherited features from `Object.prototype` which makes this a breaking change.
addaleax
left a comment
There was a problem hiding this comment.
It seems that since the object is created in C++ land, this doesn't affect it:
I don't think that check actually gives relevant information -- property accesses will still go through C++ first anyway, so the engine will not be able to fully optimize them with or without this patch
Uh oh!
There was an error while loading. Please reload this page.
devsnek
commented
Oct 22, 2019
if someone can pollute your prototypes can't they also just fs.readFile(./allYourSecrets) |
addaleax
left a comment
There was a problem hiding this comment.
This LGTM code-wise, but … I’ve thought about doing this in the past myself, and it didn’t quite seem worth the risk of breakage, esp. with hasOwnProperty(), as unfortunate as that is.
Would it maybe make sense to use a prototype chain of process.env → { hasOwnProperty: Object.prototype.hasOwnProperty } → null rather than process.env → null? It’s a bit unorthodox but it might actually be okay here?
Uh oh!
There was an error while loading. Please reload this page.
watson
commented
Oct 22, 2019
@devsnek not directly. They need to find a path from prototype pollution to remote code execution (RCE) - one which isn't always available. In #30008 I'm fixing one such path, but others almost certainly exist that we just haven't found yet. But don't get me wrong. If you have an app that's vulnerable to prototype pollution an attacker can probably do a lot of damage - if you're luckey they'll just crash the app, if you're unluckey they have found a path to do RCE. That's why I'm mostly trying to plug those holes. |
devsnek
commented
Oct 22, 2019
@watson to clarify, this is a protection against code that is not in the same process/machine? |
watson
commented
Oct 22, 2019
@devsnek I'm not sure if I understand the question fully, so I'm sorry if my answer isn't what you're looking for. This PR is about protection against prototype pollution of the |
watson
commented
Oct 22, 2019
Really interesting idea. I like it! I'll look more into this... |
Qard
commented
Dec 23, 2019
What about something like this: constlockedPrototype=Object.create(null)Object.defineProperties(lockedPrototype,Object.getOwnPropertyDescriptors(Object.prototype))Object.freeze(lockedPrototype)Object.setPrototypeOf(process.env,lockedPrototype)That gives you the full Object API, but locked to its initial state. |
BridgeAR
commented
Jan 12, 2020
What's the status here? |
8ae28ff to
2935f72Comparejasnell
commented
Jun 25, 2020
@watson ... unfortunately this appears to have stalled. Closing but we can reopen if it is picked back up again |
This removes all
Object.prototypeinherited features fromprocess.envwhich make this a breaking change (e.g.hasOwnProperty(),toString()etc). Due to this, it might not be feasible to land this PR, but I wanted to create it, if nothing else, as a forum where we could have the discussion (I could have made an issue, but already had the code ready).Why?
This is a naive attempt to protect Node.js apps a little better against prototype pollution attacks. Environment variables are often used to configure an application. They are also used to configure Node.js itself (e.g.
NODE_OPTIONS).Since prototype pollution affects all normal objects in Node.js, you could argue that we shouldn't treat
process.envin a special way. The reason I went down this rabbit hole anyway was thatprocess.envis so powerful that it might deserve special treatment.It came to my attention in #30008 that
spawnand friends from thechild_processmodule defaults to usingprocess.envif no specialenvproperty is given in options. This means that all child processes spawned can be easily attacked using prototype pollution. This of course also applies to the main process ifprocess.env.*is checked at runtime. So while the particular issue with child processes will be fixed by #30008, I felt it might be worth it fixing this forprocess.envin general.Performance
@joyeecheung raised a valid point in #node-dev on IRC about whether or not property access performance of
process.envwould be impacted if we removed the prototype. It seems that since the object is created in C++ land, this doesn't affect it:If we want to continue with this, we should consider running the benchmarks as well.
State of this PR
My C++ code might not be ideal. But at least it compiles and gets the point across. There is one failing test in
test/parallel/test-process-env.js, as that actually checks ifprocess.envinherits fromObject.prototype:node/test/parallel/test-process-env.js
Lines 41 to 42 in 31217a8
I traced that test back to fee02db, where it also seems like inheritance from
Object.prototypewas introduced (if I'm reading the C++ correctly).Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes