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

src: add process.cveRevert #52090

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mhdawson
Copy link
Member

Refs: #52017

Add API to enable CVE reverts for use in environments where the command line option cannot be used.

Refs: nodejs#52017

Add API to enable CVE reverts for use in environments
where the command line option cannot be used.

Signed-off-by: Michael Dawson <midawson@redhat.com>
@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/startup

@mhdawson mhdawson marked this pull request as draft March 15, 2024 02:21
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Mar 15, 2024
} \
#define V(code, _, __) \
do { \
if (IsReverted(SECURITY_REVERT_##code)) { \
Copy link
Member Author

Choose a reason for hiding this comment

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

This change is from running make format-cpp

Local<String> revert_error_return =
String::NewFromUtf8(env->isolate(),
revert_error.c_str(),
NewStringType::kNormal,
Copy link
Member

Choose a reason for hiding this comment

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

minor nit: might make sense to intern the string, but definitely not critical. Also, these should likely always be one-byte so maybe NewFromOneByte would work to avoid the utf8 transcoding?

@jasnell
Copy link
Member

jasnell commented Mar 17, 2024

Seems fine to me. Obviously needs tests and docs. Please ping again when you're ready for a final review :-)

@panva
Copy link
Member

panva commented Mar 17, 2024

I have a rather obvious question, what's stopping a random imported module or its dependencies from reverting these security patches without ones knowledge?

I think the opt-in only flag was the right decision at the time.

@mhdawson
Copy link
Member Author

@panva the related question would be why would not some random imported module or its dependencies from do X? The Node.js threat model (https://github.com/nodejs/node/blob/main/SECURITY.md#the-nodejs-threat-model) is that we trust code that the application asks Node.js to run. I see what you are getting out but if the code can revert a CVE it can also do a lot of other things (X in the question above) which are just as big a risk.

@mhdawson
Copy link
Member Author

@nodejs/security-triage FYI to get more input on approach.

@marco-ippolito
Copy link
Member

Can you provide an example of how it should be used?

Copy link
Member

@RafaelGSS RafaelGSS left a comment

Choose a reason for hiding this comment

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

Unless we enable it through a flag or even through the permission model, I believe this would expose vulnerabilities considering the usage of malicious packages.

I'm also curious about how this would function for reversions that are desired prior to or during Node.js startup. Let's consider a scenario where we introduce a --security-revert flag designed to set an HTTP request option to true by default. In this case, ongoing requests will persist with the default value of false, and if there's an instance of HTTPClient, it will maintain false as the default parameter post-initialization.

@mhdawson
Copy link
Member Author

@marco-ippolito the current use case is outline in #52017. For the last security release some people are not able to use the command line to revert.

@RafaelGSS it is understood that it only takes affect for things that are created after the call is made. Are you suggesting that it might not be possible to make the call in the application early enough? I could see that in some cases, but at least for the current use case if the app can be modified it should be done before any calls are made to the crypto APIs and it will work ok.

@mhdawson
Copy link
Member Author

Unless we enable it through a flag or even through the permission model, I believe this would expose vulnerabilities considering the usage of malicious packages.

Enabling through a flag would make it not useful as the whole point is because people cannot use the --security-revert command line flag. I could see it being disabled by the permission model by default.

@RafaelGSS
Copy link
Member

Unless we enable it through a flag or even through the permission model, I believe this would expose vulnerabilities considering the usage of malicious packages.

Enabling through a flag would make it not useful as the whole point is because people cannot use the --security-revert command line flag. I could see it being disabled by the permission model by default.

Do you have some scenarios where users won't be able to startup the application with --security-revert?

@marco-ippolito
Copy link
Member

Unless we enable it through a flag or even through the permission model, I believe this would expose vulnerabilities considering the usage of malicious packages.

Enabling through a flag would make it not useful as the whole point is because people cannot use the --security-revert command line flag. I could see it being disabled by the permission model by default.

Do you have some scenarios where users won't be able to startup the application with --security-revert?

I think it was mentioned that it was need for aws lambda

@RafaelGSS
Copy link
Member

Right, sorry. I didn't read the reference issue. IMO this will be a security problem. Any code will be able to revert security patches. I don't think we should address that request. If vendors want to, we could add a compile-time flag to enable this API.

@singyantam
Copy link

singyantam commented Mar 25, 2024

@RafaelGSS - Amazon is the Vendor and I do not believe they will provide any specific Nodejs runtime to address Lambda that needs to decrypt Legacy data which uses the vulnerable padding mechanism.

IMO - providing mechanism to address security risk is super good, but ideally should also allow user to address/relax it. Understood --security-revert is there already in place, but restricting it to only command line option presents challenge to users who have no access/control of the command line option easily.

Blocking all possible malicious package is noble, but should really be responsibility of users

@RafaelGSS
Copy link
Member

RafaelGSS commented Mar 25, 2024

IMO - providing mechanism to address security risk is super good, but ideally should also allow user to address/relax it. Understood --security-revert is there already in place, but restricting it to only command line option presents challenge to users who have no access/control of the command line option easily.

It's important to note that not only users will be able to perform the action in question. Any package and its dependencies that you install will also be able to perform the action, even if you don't intend for it to happen. This poses a risk for regular users. I believe that this action should only be taken when explicitly requested before the app starts up. That's why we have the --security-revert flag (which can also be passed through the NODE_OPTIONS environment variable)

@richardlau
Copy link
Member

That's why we have the --security-revert flag (which can also be passed through the NODE_OPTIONS environment variable).

Except it cannot (be used in NODE_OPTIONS). That was the original reason #52017 was opened.

@RafaelGSS
Copy link
Member

That's why we have the --security-revert flag (which can also be passed through the NODE_OPTIONS environment variable).

Except it cannot (be used in NODE_OPTIONS). That was the original reason #52017 was opened.

Hmm, so maybe that's a viable option instead of a runtime change.

@mhdawson
Copy link
Member Author

Hmm, so maybe that's a viable option instead of a runtime change.

@RafaelGSS I had thought of that to start, but looking at the history there was concern with that (from @jasnell and others) so I talked to James and what is in this PR is what we came up with as an alternative.

Allowing --security-revert in NODE_OPTIONS is a one line change if people believe that is preferable to what's in this PR but we'd need to pull in those with the original concerns to discuss again.

@RafaelGSS
Copy link
Member

Allowing --security-revert in NODE_OPTIONS is a one line change if people believe that is preferable to what's in this PR but we'd need to pull in those with the original concerns to discuss again.

I think it's worth discussing this again since we didn't have a well-defined threat model back then.

@RafaelGSS RafaelGSS added the security Issues and PRs related to security. label Mar 26, 2024
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

I think supporting it inside NODE_OPTIONS would be a safer alternative, but maybe I'm missing something.

@if-fi
Copy link

if-fi commented Mar 30, 2024

Unless we enable it through a flag or even through the permission model, I believe this would expose vulnerabilities considering the usage of malicious packages.

Enabling through a flag would make it not useful as the whole point is because people cannot use the --security-revert command line flag. I could see it being disabled by the permission model by default.

Do you have some scenarios where users won't be able to startup the application with --security-revert?

I think it was mentioned that it was need for aws lambda

We are now facing the same issue in Google Cloud Functions as well.
Would appreciate it if you add it as a NODE_OPTIONS configuration.

@mhdawson
Copy link
Member Author

mhdawson commented Apr 2, 2024

I think supporting it inside NODE_OPTIONS would be a safer alternative, but maybe I'm missing something.

I'd be ok with that but I think we'd want to pull @jasnell back into the conversaion on that.

@jasnell
Copy link
Member

jasnell commented Apr 7, 2024

My challenge with allowing it in NODE_OPTIONS is that it's too easy to set and forget and impact every instance of node that is running. Imagine, for instance someone with multiple electron apps running that pick up the flag from NODE_OPTIONS without the user actually knowing, which could put users at risk. Also consider that the reverts are specific to individual node.js major lines and a user may be running multiple Node.js major versions across multiple applications. Given it's nature, the flag needs to be explicitly opt in per-process instance and setting it as an env var circumvents that and puts users at risk.

@mhdawson
Copy link
Member Author

mhdawson commented Apr 9, 2024

@jasnell an idea had last night was what if we limit the revert to a specific Node.js version. For example considering #52365 which adds a new environment variable we also add a +version. I think that would address a few of your concerns around "too easy to set and forget and impact every instance of node that is running."

It would mean that the environment variable would only apply to a specific version of Node.js. If you have multiple versions running it would only affect the specific version you targeted. It would also mean that every time you upgrade your version you would need to update the environment variable and hopefully check if you still need it or not.

It might look something like NODE_SECURITY_REVERT=CVE-1234-456+v18.5.1+sticky

In that case it would only apply if the Node.js runtime being started is v18.5.1.

@tniessen not sure what you think about that in terms of building on what you had in #52365

@singyantam
Copy link

singyantam commented Apr 9, 2024 via email

@mhdawson
Copy link
Member Author

@singyantam would it work if it was tied only to the major version ?

@jasnell
Copy link
Member

jasnell commented Apr 10, 2024

I'm generally not a big fan of the microsyntax approach but incorporating both the major and the +stick into the value does help alleviate at least some of the concern. Unfortunately it doesn't address all of it. Say, for instance, that I am running Node.js locally and have two electron apps also running locally that are running the same major version of Node.js. And I set NODE_SECURITY_REVERT=CVS-1234-456+v20 in my environment intending to just revert the fix for my Node.js application and not realizing that it also reverted it in the two electron apps as well. Now imagine that one of those apps is being used to handle sensitive work or personal data and the unintended revert just put me at risk.

@mhdawson
Copy link
Member Author

@tniessen an FYI just so you see @jasnell last comment in terms of work on - #52365

@tniessen
Copy link
Member

@mhdawson I don't think there's a good solution for this problem. I'm not pushing for #52365 by any means — please feel free to leave it open/request changes/close it.

@mhdawson
Copy link
Member Author

mhdawson commented Apr 22, 2024

One more suggestion to see if we can find an approach most people can live with.

How about we require both

  1. a programatic request to revert a CVE as is supported in this PR
  2. AND, a command line option which can be used in NODE_OPTIONS with the sticky option as outlined by @tniessen which instead of specifying a list of CVEs, enables the the programatic cveRevert.

If people are ok with the programatic option OR if people are ok with a new command line option that can be used in NODE_OPTIONS, then I'm thinking that needing to do BOTH should be acceptable to both groups as it is tighter than either on its own.

@jasnell, @RafaelGSS, @tniessen, @marco-ippolito what do you think?

@marco-ippolito
Copy link
Member

One more suggestion to see if we can find an approach most people can live with.

How about we require both

  1. a programatic request to revert a CVE as is supported in this PR
  2. AND, a command line option which can be used in NODE_OPTIONS with the sticky option as outlined by @tniessen which instead of specifying a list of CVEs, enables the the programatic cveRevert.

If people are ok with the programatic option OR if people are ok with a new command line option that can be used in NODE_OPTIONS, then I'm thinking that needing to do BOTH should be acceptable to both groups as it is tighter than either on its own.

@jasnell, @RafaelGSS, @tniessen, @marco-ippolito what do you think?

I'm ok with having both, I think NODE_OPTIONS is required for users on serverless, and programmatic api for the remaining part

@RafaelGSS
Copy link
Member

If we look at a different perspective (as the one James is concerned) I can agree with him and it does seem a people outside of our scope. Vendors should allow command line options and that's all.

If NODE_OPTIONS will open a new threat vector for us, I think we should be careful to include it.

AND, a command line option which can be used in NODE_OPTIONS with the sticky option as outlined by @tniessen which instead of specifying a list of CVEs, enables the the programatic cveRevert.

I think it won't solve the problem but open a new attack vector, as any package will be able to revert security patches (even the most dangerous ones). I feel this is more risky than just allowing --security-revert on NODE_OPTIONS.

@marco-ippolito
Copy link
Member

If we look at a different perspective (as the one James is concerned) I can agree with him and it does seem a people outside of our scope. Vendors should allow command line options and that's all.

If NODE_OPTIONS will open a new threat vector for us, I think we should be careful to include it.

AND, a command line option which can be used in NODE_OPTIONS with the sticky option as outlined by @tniessen which instead of specifying a list of CVEs, enables the the programatic cveRevert.

I think it won't solve the problem but open a new attack vector, as any package will be able to revert security patches (even the most dangerous ones). I feel this is more risky than just allowing --security-revert on NODE_OPTIONS.

If a malicious package can control env variables it means it already has complete control

@RafaelGSS
Copy link
Member

If a malicious package can control env variables it means it already has complete control

Imagine you need to revert a specific CVE, so you enable it through ENV and then disable it programmatically. However, once the runtime API is enabled, any other CVE can be disabled. Which is different than explicitly passing --security-revert in NODE_OPTIONS IMO

@mhdawson
Copy link
Member Author

Imagine you need to revert a specific CVE, so you enable it through ENV and then disable it programmatically. However, once the runtime API is enabled, any other CVE can be disabled. Which is different than explicitly passing --security-revert in NODE_OPTIONS IMO

Ok so the follow on suggestion would be that you need to specify the CVE to be reverted in BOTH the environment variable and the cveRevert call in the code. ie the command line variable sets which CVEs are allowed to be reverted programatically and then they are only reverted if they are included in a cveRevert call.

@jasnell
Copy link
Member

jasnell commented Apr 27, 2024

One of the key issues with a programmatic API approach is that the security fix that may need to be reverted might actually apply before the user code runs... at least in theory. For instance, let's imagine that we need to make a semver major security fix that impacts the Node.js bootstrap and that somehow breaks users code. The user wants to temporarily revert the change when they run, but the change applies before any of the users code runs. In theory they might be able to use a preload module but not all vendor deployments give users that option since preloads are also configured via command line arguments.

I don't know if there's a good solution to this general problem. The revert option was always one that has been an imperfect compromise from the beginning. Ideally we wouldn't even offer such a mechanism as it shouldn't be possible for users to roll back security fixes. I'm not going to block changes here but I'm not convinced that any of the changes proposed so far are a good idea and would generally prefer to keep things as they are.

@mhdawson
Copy link
Member Author

mhdawson commented May 9, 2024

We discussed in the Security WG meeting today and the consensus was that we proceed with the proposal in #52090 (comment) versus nothing at all. It was agreed its imperfect but still better than not doing anything. Since @jasnell mentioned he'd not block although prefering the nothing option I think we can move forward with the proposal in #52090 (comment).

I think that is pulling in the changes from this PR along with the changes in #52365 that @tniessen put together with some extension to validate both.

I'll wait until next week to see if there are any other objections, otherwise, I'll talk to @tniessen how we pull the PRs together.

@JoostK
Copy link
Contributor

JoostK commented May 9, 2024

A limitation of requiring programmatic cveRevert calls in addition to an environment variable is that it cannot be propagated into subprocesses. I can see how that is a desirable trait in terms of security, but a limitation of cases where a CVE revert may need to be adopted.

@mhdawson
Copy link
Member Author

@JoostK understood there are limitations, it also won't be able to handle cases where a change needs to be reverted before user code can run. But it would have helped in the most recent case so seems to be better than nothing new.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. security Issues and PRs related to security.
Projects
None yet
Development

Successfully merging this pull request may close these issues.