GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Fixing child_process module to check values passed strictly to the options object by lirantal · Pull Request #24267 · nodejs/node

Conversation

@lirantal

@lirantal lirantal commented Nov 9, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Issue

The way the child_process module currently works with validating the extra options passed to it is by accessing the properties on the options object. However, there is no strict check to validate that the property has been defined on the direct object, and so what happens is that when accessing the property it will bubble up to the prototype chain until it hits the Object prototype and use that.

It draws attention to a possible security implication where-as the prototype chain can be manipulated and thus triggering a further vulnerability with the child_process module to execute via shell expansion which allows to execute arbitrary commands.

Reproduce

Steps To Reproduce:

  1. Create a snippet file as follows:
  const { spawn } = require('child_process');
  Object.prototype.shell = true;
  const cmd = 'ls'
  const args = ['; echo baz']
  const ls = spawn(cmd, args, {stdio: 'inherit'}, function(a,b,c) {
    console.log(a, b, c)
  });
  1. Run it
  2. Observe the baz word added to the output even though the options passed to spawn don't directly include the shell option
Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

bricss reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@nodejs-github-bot nodejs-github-bot added the child_process Issues and PRs related to the child_process subsystem. label Nov 9, 2018
@lirantal

lirantal commented Nov 9, 2018

Copy link
Copy Markdown
Member Author

/cc @cjihrig @mcollina following up on the previously submitted report.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mcollina mcollina added the semver-major PRs that contain breaking changes and should be released in the next major version. label Nov 9, 2018
@mcollina

mcollina commented Nov 9, 2018

Copy link
Copy Markdown
Member

Tagging as semver-major because of possible breakage.

I think this change should be documented.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cjihrig
cjihrig reviewed Nov 9, 2018
View reviewed changes

@cjihrig cjihrig left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM. It would be nice to try cloning the options with Object.create(null). If that works, we could avoid needing to check hasOwnProperty() for shell and potentially other options in the future.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread test/parallel/test-child-process-spawn-shell.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/child_process.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/child_process.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Nov 9, 2018

Copy link
Copy Markdown
Member Author

I think this change should be documented.

@mcollina Sure. Could you share with me what you were thinking in terms of documenting it, and where?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Nov 9, 2018

Copy link
Copy Markdown
Member Author

@cjihrig I updated the tests and code, everything is passing locally so I pushed the changes.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

jasnell
jasnell reviewed Nov 10, 2018
View reviewed changes
Comment thread lib/child_process.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

jasnell
jasnell reviewed Nov 10, 2018
View reviewed changes
Comment thread lib/child_process.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

@lirantal
child_process: fix options to check explicit values
fc9486e
cjihrig
cjihrig reviewed Nov 10, 2018
View reviewed changes
Comment thread lib/child_process.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread test/parallel/test-child-process-execfile.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread test/parallel/test-child-process-spawn-shell.js Resolved

Uh oh!

There was an error while loading. Please reload this page.

@lirantal
fix: comments and assertion fixes
61fbcad
cjihrig
cjihrig approved these changes Nov 10, 2018
View reviewed changes
BridgeAR
BridgeAR approved these changes Nov 12, 2018
View reviewed changes
@Trott

Trott commented Nov 20, 2018

Copy link
Copy Markdown
Member

This needs one more @nodejs/tsc approval and a CITGM run.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@richardlau richardlau added the needs-citgm PRs that need a CITGM CI run. label Nov 21, 2018
@rvagg

rvagg commented Nov 22, 2018

Copy link
Copy Markdown
Member

Isn't there a rabbit hole here? if we accept this then won't we be up for changing a lot of options objects? Is there something that can strictly isolate this to child_process that couldn't be argued for any other API? If it's about security, then what about vm where you could slip in some cachedData via the same method? And why are you letting wild prototype chains near your options objects anyway? Node has a long history of caveat emptor on such matters, Node isn't a sandbox, it's not your browser.

Don't get me wrong, I'd love if all our APIs were really strict, on own-properties as well as types, but they aren't and this is a really big ship to turn around so we'd better be absolutely sure we're up for that pain.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

mcollina
mcollina approved these changes Nov 22, 2018
View reviewed changes

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mcollina

mcollina commented Nov 22, 2018

Copy link
Copy Markdown
Member

CITGM: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/1642/
CI: https://ci.nodejs.org/job/node-test-pull-request/18881/

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mcollina

mcollina commented Nov 22, 2018

Copy link
Copy Markdown
Member

@rvagg I don't think we should do this everywhere, but in this specific case this makes harder to escalate a security vulnerability on an http route for example.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rvagg

rvagg commented Nov 23, 2018

Copy link
Copy Markdown
Member

@mcollina so do you have a limiting principle? Or are you just happy to roll on a case-by-case basis? I'm not a fan of pragmatism on such matters and would rather have a principle which we can apply across the board. Otherwise we're in for (a) a lot of discussion and argument for the many other options and (b) lots of code churn and semver-major breakage because we don't have a limiting principle and will therefore likely be applying similar changes across our API (vm is another example where you could make a "security" case but I reckon it wouldn't be hard to make such a case broadly across our API).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@refack

refack commented Nov 23, 2018

Copy link
Copy Markdown
Contributor

IIUC this is an issue that crops up every once in a while (#12956, and #12981) in that the core lib lives in the same domain as user code, so monkey-patching can violate many assumptions.
For example in this case the user can hijack Object.assign and circumvent this guard?

> Object._assign = Object.assign;
> Object.assign = (a, b) => Object._assign(a, b, {shell: true})
> var o = Object.assign(Object.create(null), {a:1})
> o
[Object: null prototype] { a: 1, shell: true }
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Dec 1, 2018

Copy link
Copy Markdown
Member Author

I understand that the counter-argument is that the prototype chain is the building block of the language and where you're going with theoretically requiring to make this change elsewhere as well.

With that said, this type of issue came up through a related vulnerability reported to the ecosystem, which I later brought up to the node core security team and eventually agreed to accept it as a pull request that conforms with secure coding practices rather than an actual vulnerability. At the very least, the programmer's intention in the context of the modified code was to explicitly check a property was set on the argument it received.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mcollina

mcollina commented Dec 1, 2018

Copy link
Copy Markdown
Member

@rvagg I don't, and I think this needs to be done on a case-by-case basis. I'm fine in not landing this as long as we spell clearly that this type of things are not a security vulnerability in our threat model.

Do you want to talk about this in the next tsc meeting?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rvagg

rvagg commented Dec 1, 2018

Copy link
Copy Markdown
Member

I think TSC discussion would be a good thing, this is one of those topics that has broader impact.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rvagg rvagg added the tsc-agenda Issues and PRs to discuss during Technical Steering Committee meetings. label Dec 2, 2018
@mhdawson mhdawson mentioned this pull request Dec 3, 2018
Node.js Foundation Technical Steering Committee (TSC) Meeting 2018-12-05 nodejs/TSC#637
Closed
mcollina
mcollina requested changes Dec 3, 2018
View reviewed changes

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm -1 on landing this without a @nodejs/tsc discussion about this topic.

(I'm ok with the actual change, and this -1 is only to avoid this being landed without that discussion)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@joyeecheung

joyeecheung commented Dec 5, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

@lirantal Can you elaborate on whether this particular API is more vulnerable than the others that also accept an option object? If it's not any more vulnerable in generable, or does not have more serious security implications, then from a maintenance viewpoint I'd prefer we do this in a central place for all the options (or most of them) in our API.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mcollina mcollina mentioned this pull request Dec 11, 2018
Node.js Foundation Node.js Foundation Technical Steering Committee (TSC) Meeting 2018-12-12 nodejs/TSC#639
Closed
gabrielschulhof
gabrielschulhof requested changes Dec 12, 2018
View reviewed changes

@gabrielschulhof gabrielschulhof left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Object.prototype and an own property are not the only two places where a value can be stored. There may be a legitimate prototype chain such that there is a prototype in between Object.prototype and the object itself. IOW a property on the options object may legitimately not be an own property. With this change we'd be expressing an opinion that doesn't really give us any more security because of all the other changes we'd have to make, like also addressing #24267 (comment).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mcollina

mcollina commented Dec 12, 2018

Copy link
Copy Markdown
Member

In any case, it would be good to have our threat model documented in https://github.com/nodejs/node/blob/master/SECURITY.md.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mcollina

mcollina commented Dec 12, 2018

Copy link
Copy Markdown
Member

@lirantal would you be able to join the next TSC meeting to present this pull request, and why doing this change is worthwhile?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ChALkeR

ChALkeR commented Dec 12, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

@mcollina @gabrielschulhof Do you have any example that would be broken by this particular change?


That said, protecting against malicious Object.prototype modifications is not much useful in general.

  1. Object.prototype modification is not trivial to achieve. Yes, I am aware about bugs in some libraries that made that possible — but those was security issues that were possible to be fixed.
  2. Just too much could be broken with malicious Object.prototype modifications — not only Node.js core, but most of the libraries out there on npm do not expect that and could be terribly broken in a similar way once the attacker achieves Object.prototype modification. For real-world apps, this fix would most likely cover a tiny portion of the attack surface in that aspect.

I don't think that hardening against malicious Object.prototype modifications is achievable to a sufficient level or that it is worth the amount of changes in all the ecosystem libs. Knowing that fixing the bugs that allow that modification is relatively simple.

I am not against this particular PR, in fact, I lean forward to that we should land it (if it won't cause actual breakage).
But I don't think that it's worth rewriting everything to safeguard against Object.prototype modifications.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mcollina

mcollina commented Dec 12, 2018

Copy link
Copy Markdown
Member

I'm -1 only for having this discussion. I'm +0 on the change itself.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhdawson mhdawson mentioned this pull request Dec 17, 2018
Node.js Foundation Technical Steering Committee (TSC) Meeting 2018-12-19 nodejs/TSC#641
Closed
@lirantal

lirantal commented Dec 17, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Apologies for not replying sooner, my e-mail inbox didn't receive a lot of love recently.
Thanks everyone for chiming in on this thread. Just having the security discussion going around to increase awareness is worth it, regardless of the proposed change. I like @mcollina idea with regards to the threat modeling work for Node.js, which sounds like a good task for the @nodejs/security-wg folks with the help of the TSC.

I believe the thread comments summarize it well - an unauthorized access to manipulate the prototype chain will probably break many things anyway, and I don't think we're trying to solve here prototype manipulations across all of node.

If we're not 100% to land because of code conventions between this place and others in the code-base I'm ok, but at the very least the change proposed in this PR is making senseful code practice.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@joyeecheung joyeecheung mentioned this pull request Dec 17, 2018
util: prevent leaking inspect internals #24971
Closed
4 tasks done
@mhdawson

mhdawson commented Dec 18, 2018

Copy link
Copy Markdown
Member

@lirantal sorry for the late notice but do you have time to come to the TSC meeting Tomorrow (Wednesday) at 4EST to participate in a discussion on this?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Dec 18, 2018

Copy link
Copy Markdown
Member Author

No worries, I should be able to make it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhdawson

mhdawson commented Dec 18, 2018

Copy link
Copy Markdown
Member

@lirantal I'll send you the information to join through email.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Dec 18, 2018

Copy link
Copy Markdown
Member Author

Sounds good, thanks!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@sam-github

sam-github commented Dec 18, 2018

Copy link
Copy Markdown
Contributor

I think that if console.log(options.SHELL) prints a string, then child_process.execFile(options) should use that string for the shell. Anything else is strange and unintuitive. If every node API was like that, people might learn to expect it, but if it is only child_process that ignores the options passed to it then the API behaviour would be pretty weird.

addaleax reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Dec 19, 2018

Copy link
Copy Markdown
Member Author

I can relate to that Sam.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Fishrock123
Fishrock123 suggested changes Dec 19, 2018
View reviewed changes

@Fishrock123 Fishrock123 left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if console.log(options.SHELL) prints a string, then child_process.execFile(options) should use that string for the shell. Anything else is strange and unintuitive. If every node API was like that, people might learn to expect it, but if it is only child_process that ignores the options passed to it then the API behaviour would be pretty weird.

I agree with Sam.

From what I can tell, the primary base concern here is that a theoretical vulnerability here would be harder to detect than just accessing child_process directly. However, any code that can do that can _(easily enough, even to hide, you did see the event-stream vuln, right?) just access child_process itself if you want to.

Back to Sam's quote: Really, there are a great number of things inherent in how JavaScript works where similar issues manifest. JavaScript itself could be 'more secure' in this and similar ways but that is a job that is on a different level than us, IMO.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@rvagg

rvagg commented Dec 19, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Is it worth considering something like util.strictify() or child_process.strict in the same pattern as util.promisify() and fs.promises. A way to take our current API and apply a strict argument checking layer to it. Check for strict types, hasOwn on options properties and everything else we can do to enforce explicitness. Make the API what it should have always been but opt-in.
Of course it increases our API surface area by quite a bit and would probably result in test suite bloat, so that's not great.
Another option might be to make all of the new promises APIs, like the ones in fs.promises and dns.promses (which are experimental and can change) strict in this same way. New API, new sanitization.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ChALkeR

ChALkeR commented Dec 19, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

/cc @nodejs/security-wg, just in case if there is more input on this topic.

Upd: sorry, hit the wrong button. :-/

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ChALkeR ChALkeR closed this Dec 19, 2018
@ChALkeR ChALkeR reopened this Dec 19, 2018
@mhdawson

mhdawson commented Dec 19, 2018

Copy link
Copy Markdown
Member

This was discussed in the TSC meeting today and the net of the discussion is that the TSC does not believe that the PR should land as the Node.js security model does not protect against these kinds of attacks and changing that in one small way while leaving the other unchanged does not add enough value to outweigh the risk of breaking existing code or setting a precedent for many similar changes.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhdawson mhdawson mentioned this pull request Dec 31, 2018
Node.js Foundation Technical Steering Committee (TSC) Meeting 2019-01-02 nodejs/TSC#644
Closed
@mhdawson mhdawson removed the tsc-agenda Issues and PRs to discuss during Technical Steering Committee meetings. label Jan 2, 2019
@mhdawson

mhdawson commented Jan 2, 2019

Copy link
Copy Markdown
Member

Removing TSC agenda as we should have removed after the discussion in the last meeting.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal

lirantal commented Jul 18, 2019

Copy link
Copy Markdown
Member Author

We discussed in the TSC meeting that this shouldn't be regarded as something to be fixed and is expected behavior. Closing.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lirantal lirantal closed this Jul 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@jasnell jasnell jasnell left review comments
@mcollina mcollina mcollina requested changes
@gabrielschulhof gabrielschulhof gabrielschulhof requested changes
@cjihrig cjihrig cjihrig approved these changes
@BridgeAR BridgeAR BridgeAR approved these changes
+1 more reviewer
@Fishrock123 Fishrock123 Fishrock123 requested changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

child_process Issues and PRs related to the child_process subsystem. needs-citgm PRs that need a CITGM CI run. semver-major PRs that contain breaking changes and should be released in the next major version.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

16 participants

@lirantal @mcollina @Trott @rvagg @refack @joyeecheung @ChALkeR @mhdawson @sam-github @jasnell @gabrielschulhof @Fishrock123 @cjihrig @BridgeAR @richardlau @nodejs-github-bot
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.