Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies

While looking at a package.json from a public project from PayPal, Alex Birsan noticed that it held some references to private NPM packages used internally by PayPal.

Birsan noticed some of the manifest file packages were not present on the public npm repository but were instead PayPal’s privately created npm packages, used and stored internally by the company.

On seeing this, the researcher wondered, should a package by the same name exist in the public npm repository, in addition to a private NodeJS repository, which one would get priority?

And of course, as you can guess:

Should a dependency package used by an application exist in both a public open-source repository and your private build, the public package would get priority and be pulled instead — without needing any action from the developer.

OH. SH*T. 😳

Using a preinstall script he then logged some info on his server, cleverly abusing DNS to bypass any firewalling.

Researcher hacks over 35 tech firms in novel supply chain attack →
Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies →

Super fast npm install on Github Actions

The folks at Voorhoede share how they integrated the actions/[email protected] build step into their GitHub Workflow so that it caches npm install results.

Super fast npm install on Github Actions →

Easily install local NPM packages by simply referring to their local path

Directly installing a package with npm install and referring to its local path is a quick way to work with a local package. To be safe though, the usage of npm link is still recommended.

To work with local NPM packages on can reside to using npm link. You make a package available locally with npm link and later on symlink it into your project using npm link package:

cd ~/projects/node-redis    # go into the package directory
npm link                    # creates global link

cd ~/projects/node-bloggy   # go into some project directory
npm link redis              # link-install the redis package (by its name)

This methods works fine and – above all – allows you to have a package.json that has no record of that link. That way you can check it into Git and push it, while still using the local version.

A downside however is that this way of working change is not explicit: by checking your package.json you can’t really tell whether you’re using a locally linked version or not.

~

A more easy quick and dirty way of achieving this is to directly install a package by simply referring to its directory:

cd ~/projects/node-bloggy   # go into some project directory
npm install ../node-redis   # install the redis package by referring to its directory

Apart from symlinking the package into your project, your package.json will have been adjusted like this:

{
  …
  "dependencies": {
    "redis": "file:../node-redis"
  }
}

This change is explicit: a look at your package.json clearly tells you that you’re using a locally installed package.

⚠️ Do note that this way of working comes with a big caveat though: you may not commit this change into Git. While this change Works Fine on my Machine™ it won’t in your build system, your colleague their machine, …

~

So which technique to use when? Personally I go for:

  • npm link when adjusting an existing library (most likely a clone/fork to land a bugfix) while testing it in an existing project
  • npm install ../path when splitting off a new library from an existing project

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

GitHub acquires npm

It was suggested that Microsoft/GitHub should have bought npm back in the day, instead of launching their own registry. Today is the day they’ve actually done it:

We at GitHub are honored to be part of the next chapter of npm’s story and to help npm continue to scale to meet the needs of the fast-growing JavaScript community.

For the millions of developers who use the public npm registry every day, npm will always be available and always be free. Looking further ahead, we’ll integrate GitHub and npm to improve the security of the open source software supply chain, and enable you to trace a change from a GitHub pull request to the npm package version that fixed it.

npm is joining GitHub →

Beware when merging Pull Requests with a changed lockfile

When watching a diff that contains a lockfile (say: a yarn.lock for example) on GitHub, GitHub doesn’t always show the differences (see screenshot above) as the changes in such files tend to be quite big. And even if it were to show the changes, does one really take a close look into it? With this in mind, Liran Tal started playing around to create a vector of attack using those lock files.

Take this diff for example:

What becomes clear when you look closer, is that I replaced the original ms npm package to resolve it with my own version, which is stored in my GitHub repository. I should have gotten it from the official npm registry, just as was originally set in the lockfile of the project.

When this pull request gets merged, I inject my malicious version of [email protected] into the code in order to control its behavior during runtime.

In this way, I could introduce a backdoor, alter the logic of the ms module or I could run some postinstall scripts.

To prevent such commits from being merged, you can resort to lockfile-lint which will warn you for such issues.

As an end-user it’s wise to run npm install with --ignore-scripts.

Why npm lockfiles can be a security blindspot for injecting malicious modules →

Wombat Dressing Room, an npm publication proxy on GCP

When automating the publishing of an NPM package, 2FA can get in the way, as you can’t really automate entering a 2FA auth code off a cellphone. Enter Wombat Dressing Room from Google:

With Wombat Dressing Room, rather than an individual configuring two factor authentication in an authenticator app, 2FA is managed by a shared proxy server..

  • You publish to Wombat Dressing Room, and it enforces additional security rules, before redirecting to registry.npmjs.org.
  • Publishes are made from a single npm account with 2FA enabled (a bot account).
  • Publishes can be made using the npm CLI, by making Wombat Dressing Room the default registry (npm config set registry https://external-project.appspot.com).

The Wombat Dressing Room is deployed to Google App Engine. They’ve been using it themselves internally for over a year, in case you were wondering if it is “production ready”.

Wombat Dressing Room Introductory Post →
Wombat Dressing Room Proxy Source (GitHub) →

Use a Github repository branch or commit as a dependency in package.json

Recently I needed to test a branch of a forked GitHub repository inside a project. Instead of cloning the fork and symlinking the package locally, I installed the remote dependency directly into the project.

To achieve I used the following command:

Using NPM:

npm install user/repo.git#branchname

Using Yarn:

yarn add ssh://[email protected]:user/repo.git#branchname

💡 If you’re targeting a specific commit or tag, replace branchname with the commmithash or tagname

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Programmatically add scripts to package.json with npm-add-script

Recently I needed to automate the addition of the addition of a script defined in a package.json‘s scripts section. To do this I used npm-add-script (an older, but still functioning project), along with the aforementioned npx.

For example, to add a script labelled start with the contents webpack-dev-server --config ./config/webpack.config.babel.js --env.MODE=development --open --hot, I use:

npx npm-add-script \
  -k "start" \
  -v "webpack-dev-server --config ./config/webpack.config.babel.js --env.MODE=development --open --hot" \
  --force

Using the --force I enforce overwriting of any existing start script.

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Find the cost of adding a npm package to your bundle with BundlePhobia

Ever wondered what the (size) impact of adding an NPM package to your project is? BundlePhobia is a tool that does not only that, it also recommends you other similar packages that have a lesser load.

This thing lets you understand the performance cost of npm install‘ing a new npm package before actually adding it to your bundle.

BundlePhobia →

The Economics of Open Source // Introducing Entropic, a federated package registry

At JSConf EU 2019, CJ Silverio – former CTO at NPM Inc – gave this talk on why a VC-funded private package registry (read: the one ran by NPM Inc) holds many dangers.

The JS package commons is in the hands of a for-profit entity. We trust NPM Inc with our shared code, but we have no way to hold NPM Inc accountable for its behavior. A trust-based system cannot function without accountability, but somebody still has to pay for the servers. How did we get here, and what should JavaScript do now?

At the end of the talk she announced Entropic, a federated package registry for anything; but mostly JavaScript.

Entropic assumes many registries co-existing and interoperating as a part of your normal workflow. All Entropic packages are namespaced, and a full Entropic package spec also includes the hostname of its registry.

Entropic: a federated package registry for anything →