NPM Audit: A Complete Guide to How It Works - Part 1
Tags: npm, node
Published: 2020-05-29 20:28:17


Recently, I began working with a research lab to help them with their front-end architecture. In the process of refactoring their build process, I came across this message almost half a dozen times.

```javascript
found 611 vulnerabilities (600 low, 4 moderate, 7 high)
  run `npm audit fix` to fix them, or `npm audit` for details
```

That number of vulnerabilities was initially over 15,000 and after running `npm audit` and `npm audit fix` a couple of times, I had a sense of accomplishment.

<div class="center-align">

![I did it!](https://media.giphy.com/media/l41Ye5dhLPqILtT2w/giphy.gif)

</div>

#### But, what exactly did I do? 

In this two part article, I dive into exactly that. This article helps you understand how `npm audit` works, while Part 2 wraps it up with what the `--fix` flag specifically does. So let's get started.

## NPM AUDIT
 
If you have never heard of the command before, `npm audit` helps you find (and fix) security vulnerabilities in your project's dependency tree.
  
To begin with, npm audit, needs two files to be present - `package.json` and `package-lock.json`.

Without those, you'll run into either of the two:
```javascript
npm ERR! code EAUDITNOPJSON
npm ERR! audit No package.json found: Cannot audit a project without a package.json
```

```javascript
npm ERR! code EAUDITNOLOCK
npm ERR! audit Neither npm-shrinkwrap.json nor package-lock.json found: Cannot audit a project without a lockfile
```
If you don't know how to create a package-lock.json file, you can run this command : 
```javascript
npm i --package-lock-only
```


#### So why does it need these two files?

NPM fetches the dependencies and dev dependencies by reading both these files. In the absence of the package-lock.json file, it uses the [npm-shrinkwrap.json](https://docs.npmjs.com/cli/shrinkwrap) file.It also uses the shrinkwrap file if both of the files are present. If you want to see exactly how this is done, here is a link to the [audit.js file](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/lib/audit.js#L157) in the NPM repository. The dependencies from the package-json file and the contents of the package-lock file are passed to a function called [audit.generate()](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/lib/install/audit.js#L122) in the form of parameters called require and sw.

#### Okay, what next?

In the generate function, a deep clone of the shrinkwrap(or package-lock) file is created. After passing the inputs through a series of functions to scrub and sanitize the data, an object is created containing two keys, namely `requires` and `dependencies`. You can checkout the code on [how the data is scrubbed here](https://github.com/npm/cli/blob/abdf52879fcf0e0f534ad977931f6935f5d1dce3/lib/install/audit.js#L140). The require and dependencies keys enumerate the packages required in the project along with their version, integrity(the hash) and more information.


Once it has made this object, npm calls the `audit.submitForFullReport(auditReport)` function. This makes a POST request to `https://registry.npmjs.org/-/npm/v1/security/audits` with this JSON object as the body. NPM Audit uses the [npm-registry-fetch package](https://www.npmjs.com/package/npm-registry-fetch) for this.

Here is a sample request body of the data sent across: 

```javascript
{
	"name":"package-name",
	"version":"1.0.0",
	"requires":{
		"http-proxy": "1.18.0"
	},
	"dependencies":{
		"http-proxy": {
	      "version": "1.18.0"
		}
	}
}
```

The response of this API call returns detailed information on any reported warnings and vulnerabilities contained in your repository after checking them with your registry. In most cases, this registry is NPM.

Below, you will see a sample response for the request body from above. We see a sample vulnerability in [http-proxy](https://www.npmjs.com/package/http-proxy). Each such object contains information about who it was reported by, the relevant dates and more about the finding.

```javascript
["1486": {
            "findings": [
                {
                    "version": "1.18.0",
                    "paths": [
                        "http-proxy"
                    ]
                }
            ],
            "id": 1486,
            "created": "2020-02-21T14:16:24.023Z",
            "updated": "2020-05-18T14:50:08.944Z",
            "deleted": null,
            "title": "Denial of Service",
            "found_by": {
                "link": "https://twitter.com/_awry",
                "name": "Grant Murphy",
                "email": ""
            },
            "reported_by": {
                "link": "https://twitter.com/_awry",
                "name": "Grant Murphy",
                "email": ""
            },
            "module_name": "http-proxy",
            "cves": [],
            "vulnerable_versions": "<1.18.1",
            "patched_versions": ">=1.18.1",
            "overview": "Versions of `http-proxy` prior to 1.18.1 are vulnerable to Denial of Service. An HTTP request with a long body triggers an `ERR_HTTP_HEADERS_SENT` unhandled exception that crashes the proxy server. This is only possible when the proxy server sets headers in the proxy request using the `proxyReq.setHeader` function.   \n\nFor a proxy server running on `http://localhost:3000`, the following curl request triggers the unhandled exception:  \n```curl -XPOST http://localhost:3000 -d \"$(python -c 'print(\"x\"*1025)')\"```",
            "recommendation": "Upgrade to version 1.18.1 or later",
            "references": "- [Patch PR](https://github.com/http-party/node-http-proxy/pull/1447/files)",
            "access": "public",
            "severity": "high",
            "cwe": "CWE-400",
            "metadata": {
                "module_type": "",
                "exploitability": 4,
                "affected_components": ""
            },
            "url": "https://npmjs.com/advisories/1486"
        }]

```

Finally, after collating all this information and grouping the issues based on their seriousness, NPM typically calls `audit.printFullReport(auditResult)` which prints the report as you see it on the screen. To do this, NPM uses a package called the [npm audit report](https://www.npmjs.com/package/npm-audit-report).  

And that's how you see the outfit that you're familiar with.

```
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ minimist                                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=0.2.1 <1.0.0 || >=1.2.3                                    │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ react-scripts                                                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ react-scripts > jest > jest-cli > jest-config > babel-jest > │
│               │ @jest/transform > jest-haste-map > fsevents > node-pre-gyp > │
│               │ rc > minimist                                                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/1179                            │
└───────────────┴──────────────────────────────────────────────────────────────┘

```

In Part 2 of this article, I dive into how the `--fix` flag works. Adding a link soon!

Did you like this article? Let me know on <a href="https://twitter.com/SatejSawant">Twitter</a> at <a href="https://twitter.com/SatejSawant">@SatejSawant</a>. If you spot something incorrect, please write to me at satejs93[at]gmail[dot]com.


I referred to a couple of resources while writing this article. Here they are:

- https://github.com/npm/cli/blob/latest/lib/audit.js
- https://www.npmjs.com/package/npm-audit-report
- https://www.gyanblog.com/gyan/how-node-npm-audit-rest-api-vulnerability/
- https://www.w3resource.com/npm/how-to-run-a-security-audit-with-npm-audit.php

For Part 2 of this article, refer to [this link](https://dev.to/s3cube/npm-audit-fix-the-complete-guide-to-how-it-works-part-2-4opk)