Start with a security breach

Lodash is a very popular NPM library, downloaded more than 80 million times a month and used by more than 4 million projects on GitHub. Here’s a reminder of a security flaw in Lodash that has gone viral:

An attacker can override or contaminate an application with some of Lodash’s functions. For example, you can modify the properties of Object.prototype with the Lodash library function defaultsDeep.

We all know that JavaScript reads a property in an object, and if it can’t find it, it looks up its prototype chain. Imagine if the property being modified was the toString method:

const payload = '{"constructor": {"prototype": {"toString": true}}}'
_.defaultsDeep({}, JSON.parse(payload))
Copy the code

Each object has a toString() method, which is called automatically when the object is represented as a text value, or when an object is referenced as an expected string. By default, the toString() method is inherited by each Object. If this method is not overridden in a custom object, toString() returns [Object type], where type is the type of the object. Overwriting the toString() method can have a significant impact on the application.

In fact, the above problem is a very common security vulnerability – prototype contamination

Prototype contamination: An attacker modifies the prototype of a JavaScript object by some means

This isn’t the first time Lodash has had a security breach, however. In fact, security vulnerabilities like these can exist in the millions of different open source dependencies we use, and if we don’t pay attention to them, the damage to our projects is incalculable. It’s the equivalent of having a lot of bombs buried in your project that you don’t know when they’re going to go off.

Security clearance

Developers trust the security of open source code more than they trust the security of code they write, but the tools available to ensure code safety and quality leave a lot to be desired. Before NPM had a comprehensive security check mechanism, NPM and the NodeJs team conducted a survey of tens of thousands of JavaScript developers. The first question was about security, specifically how developers felt about the security of the code they wrote and the open source projects they used.

The results show that 97% of JavaScript developers around the world rely on open source code for their projects, and 77% are concerned about the security of the open source code they use. More interestingly, 87 percent said they were concerned about the security of their code.

In addition, more than half of JavaScript developers believe that the tools they use to evaluate the security and quality of open source code are not good enough.

npm audit

Based on the less-than-positive findings above, npm@6 has added a major update: the NPM audit command. As you can see from the logo, this version is all about security. The NPM audit command recursively analyzes the dependency tree to identify insecure dependencies, and if you use dependencies with known security issues in your project, you get a warning notification. This command will run automatically when you update or install new dependencies.

The NPM official maintains a list of vulnerabilities. When developers or professional security teams find security problems in a dependency package, they will report to the NPM official, and then the official will notify the developers of the project to fix them. After the repair, NPM will publish detailed descriptions of vulnerabilities and solutions:

NPM Aduit sends the dependency information that needs to be checked to an official inspection interface. This structure determines whether the current dependency information contains vulnerabilities in the historical vulnerability database, and then generates a vulnerability report containing the package name, vulnerability severity, profile, and path for the developer.

We are now going to install a version of [email protected] with a security vulnerability that will alert you to the three vulnerabilities in the dependency you just added.

This version of LoDash has 3 vulnerabilities. Let’s take a look at one of them:

  • High: Indicates the level of security vulnerability
  • Package: Indicates the name of the package with the vulnerability
  • Dependency of: Specifies the package name on which the current project directly depends
  • Path: Vulnerability completely depends on the path
  • More info: Vulnerability details

Note that it’s not just the directly dependent packages that have vulnerabilities that get alerts. Instead, you get alerts whenever a node in your dependency tree relies on a vulnerable package. Here’s an example:

If loDash is not directly relied on in a project, it counts as a bug if loDash is relied on in @commitLint/LOAD, so it is not uncommon for large projects with long iterations to have tens of thousands of security holes.

Point open hole details link: https://www.npmjs.com/advisories/1065

We can see the detailed description of the vulnerability and the solution. On the right side are the specific reporting time and disclosure time of the vulnerability.

GitHub Security

It’s not unusual to receive a GitHub security alert like this one.

Open the link, we can see the details of the vulnerability page:

GitHub has created a separate “Security” section for GitHub to show dependency Security vulnerabilities that GitHub has detected. These vulnerabilities are serious enough to require quick fixes:

GitHub also provides one-click fixes for each fixable vulnerability. Click the Automated Security Updates button and GitHub will automatically fix these dependency vulnerabilities and submit a Pull Request to your repository:

Security vulnerability repair policy

NPM also provides the NPM audit fix command to help us automatically fix the vulnerability. Continuing with the above example, Lodash had prototype contamination vulnerability prior to 4.17.12. Let’s look at the specific fix strategy:

Direct dependence vulnerability

Currently we rely directly on a version of [email protected] with security vulnerabilities:

"Dependencies ": {" 0 ":" 0 "}Copy the code

Since ^4.17.4 has a dependency range of >=3.0.3 < 4.0.0, and the fixed version 4.17.12 is in this range, the logic that NPM Audit Fix actually executes is NPM update [email protected].

Lodash @ ^ 4.17.4 - > lodash @ ^ 4.17.12Copy the code

Indirect dependency vulnerability

Suppose we have a very deep dependency path now: @commitLint /cli^7.1.2> @commitLint /load^1.0.1> loDash ^3.0.0

Because @commitLint/Load has a loDash dependency of ^3.0.0(>=3.0.0 <4.0.0), 4.17.12 is not in this scope, so we cannot fix the bug directly by updating LoDash.

@commitlint/ Load ^1.0.2 has a dependency on lodash that is ^4.0.0(>=4.0.0 <5.0.0), [email protected] within this dependency, NPM update @commitlint/[email protected] –depth=2

NPM update only checks the dependencies at the top level of the update, and updates the dependencies at the deeper level need to use –depth to specify the depth of the update.

Following this logic, if @commitlint/ Load also does not find a package that can be upgraded, then go back to the upper-level dependencies until it finds a dependency that can fix the bug.

Force bug fix

Follow the above strategy and work your way up from the bottom dependency to the top dependency. If you don’t have a fix all the way up to the top dependency, then update the top dependency directly.

Continuing with the example above, if @commitlint/cli^7.1.2(>=7.1.2 <8.0.0) does not find a fixable version, then the NPM audit fix command is useless.

Try NPM audit fix –force (force audit fix to install the latest dependency (toplevel)). npm install @commitlint/cli@patchedVersion –save

This command forces dependencies to be updated to the latest version of Semver directly across the currently specified version range. Use this command with caution.

NPM also provides several other repair command commands

  • npm audit fix --package-lock-only: Do not modifynode_modulesIn the case of executionaudit fix, will still changepkglock
  • npm audit fix --only=prod: Skip the updatedevDependencies

Unfixable leak

Of course, none of the above repair strategies can solve this security vulnerability, which means that this vulnerability can not be repaired automatically and requires manual decision processing.

Turn off security check

If you don’t care about these security vulnerabilities, you can also manually specify some configurations to turn these security checks off:

  • Install single package to close security review:npm install example-package-name --no-audit
  • Install all packages close security Review – runnpm set audit false
  • The manual will be~/.npmrcIn the configuration fileauditModified tofalse

Of course, this is not recommended, and you must be responsible for your own projects

Read dependency bug reports

Executing NPM Audit –json will print a detailed JSON-formatted security report with details of these vulnerabilities and the strategy for fixing them.

Since this JSON is quite large, I will not post it directly here. You can choose a project to execute NPM audit — JSON locally to view it.

Overview of vulnerability data

In the Metadata property: we can see the data overview of vulnerability inspection:

  {
    "vulnerabilities": {
      "info": 0."low": 0."moderate": 4."high": 29."critical": 0
    },
    "dependencies": 18594."devDependencies": 891090."optionalDependencies": 9514."peerDependencies": 0."totalDependencies": 909785
  }
Copy the code

The number of vulnerabilities of each level was displayed in the shapatleniency, while info, Low, Moderate, High, and Critical had the corresponding security vulnerability levels from left to right from low to high.

Below are the number of detections for each dependency, known as Dependencies, devDependencies, and so on.

Repair strategies

In the Actions property, all bugable fix strategies are listed, such as the following: update @commitlint/load to a depth of 2 to fix the bug on @commitlint/cli>@commitlint/ Load >lodash:

{
      "action": "update"."module": "@commitlint/load"."target": "1.0.2"."resolves": [{"id": 1184."path": "@commitlint/cli>@commitlint/load>lodash"."dev": false."optional": false."bundled": false}]."depth": 2
    }
Copy the code

In addition, action has the other operations we mentioned above:

  • install(Fix direct dependencies)
  • install major(Force upgrade dependencies across major versions)
  • review(Cannot be repaired automatically, manual review is required)

Vulnerability details

The Advisories property stores details of each vulnerability:

"1065": { "cves": [ "CVE-2019-10744" ], "access": "public", "severity": "high", "metadata": "", "reviewers": "", "confirmors": "", "id": 1065, "repo_from": "npm", "title": "Prototype Pollution", "module_name": "lodash", "found_by_link": "", "found_by_user_name": "Snyk Security Team", "reported_by_link": (15) ", "reported_by_user_name": "Snyk Security Team", "vulnerable_versions": "<4.17.12", "patched_versions": "> = 4.17.12", "the overview" : "Versions of 'lodash' before 4.17.12 are vulnerable to Prototype Pollution. The function 'defaultsDeep' allows a malicious user to modify the prototype of `Object` via `{constructor: {prototype: {... }}}` causing the addition or modification of an existing property that will exist on all objects.\n\n", "Recommendation ": "Update to version 4.17.12 or later "," References ": "- [Snyk Advisory](https://snyk.io/vuln/SNYK-JS-LODASH-450202)", "cwe": "CWE-471", "url": "Https://npmjs.com/advisories/1065", "gmt_create" : "the 2019-07-16 T02:28:32. 000 z", "gmt_modified" : "The 2019-09-11 T04: leave. 000 z", "deleted_at:" null, "findings" : [{" version ":" 4.17.11 ", "paths" : [ "@commitlint/cli>@commitlint/load>@commitlint/rules>@commitlint/ensure>lodash", "@commitlint/cli>@commitlint/load>lodash", "@commitlint/cli>@commitlint/load>@commitlint/resolve-extends>lodash", "@commitlint/cli>@commitlint/load>lodash", "@commitlint/cli>lodash" ], "dev": true, "optional": false, "bundled": false } ] }Copy the code

Since there are many attributes, let’s pick a few key ones to have a look:

  • cves: CVE vulnerability number
  • severity: Vulnerability level
  • found_by_user_name: The user who discovered the vulnerability (hereSnyk Security TeamIs a well-known security team)
  • vulnerable_versions: Affected version
  • patched_versions: The restored version
  • findings: All vulnerabilities that depend on this path
  • overview: A brief description of the vulnerability, mentioned hereLodashdefaultsDeepSusceptible to prototype contamination
  • references: Vulnerability reference, usually issued by some professional security platform report

Security platform

There are several professional security platforms mentioned in the above report, which are easy to confuse people. Let’s take a look at them in detail:

HackerOne

HackerOne (http://hackerone.com), founded in 2012, is a security vulnerability aggregation and disclosure platform. Hackers can disclose their security vulnerabilities on the website and report them to relevant websites or companies. These websites or companies can reward hackers with various kinds of thanks after confirming their security vulnerabilities. HackerOne has more than 300,000 registered hackers, submitted more than 100,000 valid vulnerabilities and paid out more than $42 million in bug incentives.

"references": "- [HackerOne Report](https://hackerone.com/reports/541502)"
Copy the code

As you can see in the security report, HackerOne also has a bug report for some bugs as a reference.

Snyk

Snyk is a dependency analysis platform for multiple development stacks, covering JavaScript, Java,.NET, Ruby, Python, PHP, Golang, and Scala. Snyk maintains a comprehensive, open source vulnerability database that includes vulnerabilities discovered by Snyk’s own dedicated research team, as well as those tracked from public data sources.

Snyk’s vulnerability database provides comprehensive data about vulnerabilities through its threat intelligence system, providing better coverage and the ability to display and report vulnerabilities that have not yet received CVE. For example, 72% of the vulnerabilities flagged by NPM were first added to the Snyk database.

Snyk also provides a mechanism to scan for security vulnerabilities. Compared with NPM Audit, it has the advantage that it can be easily integrated with GitHub or GitLab’S CI process. For more comparison on scanning mechanism, please refer to this article: https://www.nearform.com/blog/comparing-npm-audit-with-snyk/.

"references": "- [Snyk Advisory](https://snyk.io/vuln/SNYK-JS-LODASH-450202)"
Copy the code

As can be seen from the above security report, some vulnerabilities will also have a Vulnerability report of Snyk as a reference, and the Lodash security vulnerability is also discovered and reported by the Snyk security team.

CVE

CVE stands for the Common Vulnerability and Disclosure Standard, a nonprofit organization funded by the federal government as a research and development center. Its purpose is to identify vulnerabilities in software or firmware and catalog them in a free database to improve organizational security.

By identifying a specific vulnerability or exposure with a CVE ID, organizations can quickly and accurately obtain information from a variety of CVE-compatible information sources. By comparing different security tools and services, CVE helps organizations choose what best fits their needs.

"cves": [
        "CVE-2019-10744"
      ]
Copy the code

We can see that both the above NPM Audit report and Snyk, HackerOne and other security platform reports will attach a CVE number of vulnerability.

reference

  • Medium.com/npm-inc/sec…
  • zhuanlan.zhihu.com/p/73186974
  • zhuanlan.zhihu.com/p/27891196
  • Eux.baidu.com/blog/fe/npm…

summary

I hope after reading this article you can have the following help:

  • Understand the background of dependency security vulnerabilities
  • To understandnpmA mechanism to automatically fix security vulnerabilities
  • Learn some general security knowledge and increase your awareness of front-end security issues

If there are any mistakes in this article, please correct them in the comments section. If this article has helped you, please like it and follow it.

Want to read more quality articles, can follow my Github blog, your star✨, like and follow is my continuous creation power!

I recommend you to follow my wechat public account [Code Secret Garden] and push high-quality articles every day. We can communicate and grow together.