[BUG] NPM allows insecure code execution by configuration file
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.1k
- Forks
- 4.7k
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 19
Description
Is there an existing issue for this?
- I have searched the existing issues
This issue exists in the latest npm version
- I am using the latest npm
Current Behavior
Intro
NPM is a package manager used in our CI/CD environments, We are using it to download and install all our different dependencies inside our building phase for production.
In order to use it safely, we use some precautions, We try to minimize as much as possible its exposure to secrets but still sometimes we have no choice but to add them.
Reading the documentation here and best practices using the cli around the internet it is best to run in ci environments with npm ci --ignore-scripts which should not run any scripts, additionally, we saw that npm sees bypassing this command as a high severity
Researching this subject we found out that a developer or malicious actor with access to the codebase can in fact force npm to run scripts although we configured it explicitly to ignore scripts.
Talking with the bounty team the response was that this is not eligible for bounty and is not considered a risk as this is the intended behavior of npm.
We agree that this is a design issue, but nevertheless, this can be used as an attack vector by actors, we want to raise the issue here and understand what mitigations can we have in the meantime, and if this design will be changed in the near future?
The Issue
When adding a .npmrc file to our repo, npm will pick up the file and read its configuration. This means that any command using npm will automatically pick up the configuration file.
It is possible to inject a configuration that will then execute code in the installation context and attempt to attack the installation environment by two vectors:
- Adding
git=${PWD}/rce.shto .npmrc and adding an installation from git to the package.json, such as"dependencies": { "ini":"git://github.com./npm/ini.git#v2.0.0" }will execute the rce.sh script when runningnpm installversion 7,8 - Adding
onload-script=${PWD}/rceto .npmrc will invoke the rce.js script in the library when running ANY npm version 6 command
Expected Behavior
As we are not expecting to run any scripts when running with "--ignore-scripts" this is can and will affect our devops installations if a malicious actor gains access to parts of our codebase.
I understand that this was not the intended behavior of the flag,
but it became the only security measure in use and implies that there will be no unintended scripts running
Steps To Reproduce
Using npm version 7,8
- npm init
- npm i --save "git://github.com./npm/ini.git#v2.0.0"
- echo "git=${PWD}/test.sh" > .npmrc
- echo 'echo "HACKED!!!" > poc.txt && git $@' > test.sh
- rm -rf node_modules
Attack phase
- npm ci --ignore-scripts
- cat poc.txt
Using npm version 6
- npm init
- echo "onload-script=${PWD}/rce" > .npmrc
- echo "console.log('Hacked") > rce.js
Attack phase
- npm ci --ignore-scripts
Environment
- npm: 8.1.4
- Node: v14.15.5
- OS: OSX
- platform: Macbook Pro
- npm config:
; "user" config from /Users/rotembar/.npmrc
registry = "https://registry.npmjs.org/"
; "project" config from fuzz/npm-lion/.npmrc
git = "npm-lion/test.sh"
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the .npmrc configuration handling used by npm ci --ignore-scripts and reproduce the two reported paths: git=${PWD}/rce.sh with a git dependency in package.json, and onload-script=${PWD}/rce. Compare behavior across npm 6, 7, and 8 using the listed reproduction steps; done means the reported scripts no longer execute unexpectedly, or the supported mitigation is documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- devops, security, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100