Npm Dependency Version Syntax

broken image


On February 9, 2021, Alex Birsan disclosed his aptly named security research, dependency confusion. In his disclosure, he describes how a novel supply chain attack that exploits misconfiguration by developers, as well as design flaws of numerous package managers in the open source language-based software ecosystems, allowed him to gain access and exfiltrate data from companies such as Yelp, Tesla, Apple, Microsoft, and others.

This security research sparked attention, and with it, a new breadth of tools to help organizations detect if they are vulnerable or susceptible to potential dependency confusion attacks.

In this article, I will introduce you, step-by-step, to the dependency confusion attack and how it manifests for JavaScript and Node.js developers working in the npm ecosystem. We will also take a look at a new, open source tool from Snyk that allows you to detect potential dangerous dependency confusion implications in your own source code repositories: snync.

Pop quiz! Can you guess what snync stands for? Answer at the end…

Npm 7 is now generally available! After much anticipation, the npm CLI version 7 is now generally available! In addition to new features and some breaking changes, we have made a significant impact on the performance of npm 7 as compared to npm 6 including: Increasing our development velocity/tempo to a weekly release cadence, most notably: we. In this tutorial, we are going to learn about how to list (view) the npm installed packages and its dependencies in a tree structure in the terminal. Listing installed packages and dependencies. The npm ls command helps us to list (view) all versions of installed packages and their dependencies in the terminal. For a specific version you can use this syntax npm-remote-ls primeng@1.0.0-beta.7. Here is the unpowerful official command: npm view dependencies. If you defined a npm dependency with a constraint such as ^1.0.0 then it was an instruction to npm to use whatever the latest 1.x was at the time of installation. In what must have seemed like a good idea at the time, people reasoned that 'according to SemVer, anything in 1.x should be backwards-compatible, so it's safe to always install. This command locks down the versions of a package's dependencies so that you can control exactly which versions of each dependency will be used when your package is installed. Since npm 5, a 'package-lock.json' is automatically generated when an npm operation modifies the 'nodemodules' tree or 'package.json'.

In this article, we will learn about each of the ways this supply chain attack manifests, and detail how to mitigate each of them:

  • Private npm registry misconfiguration
  • Private npm registry fetches latest versions
  • Manual package updates may introduce malicious versions

Do dependency confusion attacks impact you?

The dependency confusion attack only works on organizations that rely on internal source code libraries. Managing private packages due to the need to maintain intellectual property is very common, and as such, many organizations find themselves using internal proxies, caches, or private package hosting registry services to do just that.

If an organization is managing an internal private package, then this package will (by definition) not exist on public registries and their mirrors. And since the private package is not listed on a public registry, anyone else is free to reserve that package name and potentially launch a dependency confusion attack against you. The fact that a private package can have the same name as a public package is what lies at the heart of this attack.

For the JavaScript and Node.js ecosystems, the dependency confusion attack surface is greatly diminished if you are relying on scoped packages as a reserved namespace. But please note that, regardless of whether you are using npm or yarn, you are vulnerable to this supply chain attack.

Replaying dependency confusion attacks

To practically explore supply chain security attacks in the form of dependency confusion, we will experiment with a hands-on tutorial that will demonstrate the vulnerability and how to mitigate against it. Star plus serial yeh hai mohabbatein all ringtone.

Npm Dependency Version Syntax

The following is the package manifest for a project known internally as the Death Star. It's a great name, I know!

This code is located in the package.json, and it also shows the dependencies of this project. As you can see, superlaser is a dependent package. Of course, this is a very secret weapon that the empire possesses, so it is only published internally. The Death Star needs to be mobile in space, and as such, it also relies on the private package death-star-secret-hyper-matter-reactor.

How to set up private npm registry

If you want to follow along at home, we have to take a quick detour from the primary article focus to set up a private npm registry. With a private registry, you can experiment on your own and replicate this dependency confusion supply chain attack end-to-end.

Npm Dependency Version Syntax Python

To do that, we will set up an internal private npm registry and proxy server using Verdaccio, an open source project for those needs. If you have Docker installed, we can spin it up rather easily as follows:

Rad studio 10.3 crack. If everything is successful, Verdaccio will then greet us:

Congratulations. You now have your own dedicated private hosting of npm packages running locally at port 4873.

Let's go ahead with publishing our secret internal npm packages superlaser and death-star-secret-hyper-matter-reactor. We will start first with adding a user to this new Verdaccio private registry:

Next is our superlaser package manifest file package.json:

The death-star-secret-hyper-matter-reactor package manifest is similar, just with a different package name. Let's go ahead with publishing it to our private npm registry:

Why does dependency confusion exist?

There are primarily three cases that could lead to this class of software supply chain attacks:

  • Misconfiguration on a developer or test server
  • Newer versions of packages published in the public npm registry
  • Arguably, design flaws in package managers

Let's revisit each of these cases.

Private npm registry misconfiguration

When a developer or a continuous integration (CI) system clones the source code of the the-death-star project — which has the internal superlaser dependency — how does it obtain this dependency?

It likely needs to satisfy the following criteria when an npm install command is invoked:

  1. It needs the URL of the private npm registry where this internal package exists.
  2. It needs a token or credentials of some sort to access that private registry.

The very first step outlined above is where things can go wrong. To specify a particular private npm registry, one needs to explicitly provide configuration information for the npm package manager.

Now let's revisit some scenarios:

  1. What happens if the continuous integration system doesn't have the private registry set?
  2. What happens if you are a new developer onboarding to an existing project and you did not undergo prior steps such as running the command npm config set registry ?
  3. What happens if you mistakenly removed or changed your .npmrc configuration to not include the internal private npm registry?

In any of these cases, where the custom setting for an internal registry was omitted, the npm package manager will default to the public registry (registry.npmjs.org) and will download packages from that.

Anyone can publish packages on the public npm registry, and so, if a malicious user were to publish a package named superlaser, then it would've been downloaded and installed instead of your own internal package.

How to protect against npm dependency confusion

The core issue resides with the concern of not having the proper private npm proxy configuration. If a developer, or a CI system, misses on having this configuration, then you're potentially vulnerable.

So the first step is: Always ensure that a .npmrc file is made available, or another form of the private npm proxy configuration.

Secondly, you can take a proactive approach that detects cases in which you are using private packages that have their namespace unreserved on the public npmjs registry. We built snync to help you with that. You can run it in a CI server as part of the steps, before you actively install dependencies. This way, it can protect you from mistakenly installing a malicious package.

In the following screenshot, I am running snync vianpx and providing it with the current directory to scan for dependencies, as well as specifying that the package named superlaser is indeed a private package:

As you can see in the results, snync confirmed for me two particular cases of potential issues of dependency confusion:

  1. The death-star-secret-hyper-matter-reactorpackage is vulnerable because there's no package of this name that is registered at the moment on the public npmjs registry. It means that anyone can register it and then a dependency confusion attack can take place.
  2. The superlaser package is suspicious. This means, that the tool detected one of two cases:
    1. This package name was first introduced to the Git source code, and only later in time, a package of the same name was published to the public npmjs registry. This doesn't mean that the public package on the npmjs registry is malicious, but warrants a review.
    2. The package name already exists on the public npmjs registry, even before you created a package of the same name as a private one.

snync is an open source Node.js-based command line project, and we invite you to use it for your DevSecOps security pipeline.

Private npm registry fetches latest versions

What happens if there's a package of the same name of ours (superlaser) that is published and available in the public npm registry, but has a higher semver version?

To illustrate, the situation is as follows:

  • superlaser@1.0.0 exists in private npm registry https://localhost:4783
  • superlaser@1.99.999 published by anonymous user to public npm registry at https://www.npmjs.com/package/superlaser

Now the question is, what happens if a new project is scaffolded and requests to install the superlaser package? There's no package.json yet, there's no lock file yet (package-lock.json). A developer simply starts off with:

This install potentially ends with a malicious version of superlaser which a remote attacker controls. But why? The developer has the local npm registry configured.

As testing shows, even if an internal npm private proxy is configured, it has been observed that the behavior of many of these proxies is to first check the newest version available in the npm public registry. If such a newer version exists, these proxies fetch the newest semver version of the package from the public registry and install that. Best python installation for mac brew conda.

Let's replicate this scenario with Verdaccio. As you can see below, I have pushed the harmless superlaser npm package to Verdaccio, which serves my purposes as an internal hosting of private npm packages:

Next, I'll show you how in a new project directory that only has the.npmrc file pointing to the local Verdaccio registry, an npm install command for the superlaser package fetches the latest version from the public npm registry, even though I was expecting that I will just get superlaser@1.0.0 which is what I have published internally:

This creates an unexpected result and may potentially put end-users at risk.

Note, there is a public discussion in the open source Verdaccio project at GitHub about this behavior if you wish to participate and follow-up on this topic.

Technically, this process taken by Verdaccio and other private npm proxies, takes into account several variables, such as:

Npm Dependency Version Syntax Example

  1. The latest semver release
  2. The time the package was published

So, for example, if a high semver version exists on the public npmjs registry, yet a package of the same name with a lower semver version (of the same range as the public one) is created after the publish date of the high version, then Verdaccio will not fetch the public registry package.

How to protect against fetching the wrong package

Configure your private npm proxy to never proxy requests upstream to the public registries. If a package or version is not available locally, it should be resolved in a way that doesn't blindly fetch packages from untrusted and unvetted sources.

If you are using Verdaccio, like in our examples here, you can do it like so with the following configuration that resides in /verdaccio/conf/config.yaml:

The above is the stock Verdaccio configuration file for the Docker container version of it, except that you can locate the # DO NOT FETCH PACKAGES FROM NPMJS comment which on the next line comments the proxy: npmjs option. This blocks Verdaccio from fetching anything from npmjs for the packages set by the matching pattern.

Manual package updates may introduce malicious versions

In this scenario, you are manually updating your npm packages by running npm update or npm install @latest to bring your dependencies versions up to date.

When you invoke these update procedures, then the same behavior that we witnessed before takes place here too. The npm update command asks the private npm proxy to fetch the latest version, which in turn, the proxy checks for the most up-to-date version on the public npm registry.

Npm Dependency Version Syntax

Note, if you're a yarn user, then issuing a yarn upgrade will yield the same result of pulling in the potentially malicious packages from the public npmjs registry.

We can demonstrate it in the following scenario, where we start off with the internal superlaser@1.0.0 version:

Now, I do have a .npmrc file which defines the local registry and is pointing to the Verdaccio server I have running. Yet, if I simply run npm update to bring all of my dependencies up to date, you can see it pulls in the latest semver matching version from the public npmjs registry:

How to protect against it?

Instead of manual and blind npm package updates, opt-in for automated package updates in the form of pull requests raised to your open source project repositories, which will also take care of syncing the package manifest (such as package-lock.json or yarn.lock).

Snyk is one way you can freely automate npm package updates, as the following screenshot of a merged pull request shows:

You can further fine-tune the automated update settings, such as limiting the number of pull requests that Snyk will open, or to completely ignore updating specific packages. There's more on that in Snyk's documentation on upgrading dependencies with automatic PRs.

Prevent dependency confusion with Snyk

Keep your applications safe from supply chain security vulnerabilities for free.

Concluding with application security resources

If you made it this far along, you've earned the answer to the quiz we presented at the beginning of the article. We named the open source tool snync as an abbreviation for So Now You're Not Confused. Did you get it?

Practicing secure methodologies, whether as writing code, or day to day developer security hygiene, can't be stressed enough these days with supply chain security incidents. If you or your team are doing JavaScript or Node.js regularly then you'll find these reference resources useful:





broken image