Skip to content

Commit 7a5cf6f

Browse files
authored
Merge pull request #175 from AlexHladin/add-npm7-support
Add npm7 support
2 parents 6e9dff3 + ef20688 commit 7a5cf6f

18 files changed

+1186
-95
lines changed

lib/Model.js

+36-13
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,53 @@ class Model {
4444
return;
4545
}
4646

47-
advisory.findings.forEach((finding) =>
48-
finding.paths.forEach((path) => {
49-
if (this.allowlist.paths.includes(`${advisory.id}|${path}`)) {
50-
this.allowlistedPathsFound.push(`${advisory.id}|${path}`);
51-
}
52-
})
47+
this.allowlistedPathsFound.push(
48+
...advisory.findings
49+
.map((finding) => `${advisory.id}|${finding.paths}`)
50+
.filter((path) => this.allowlist.paths.includes(path))
5351
);
5452

55-
if (
56-
advisory.findings.every((finding) =>
57-
finding.paths.every((path) =>
58-
this.allowlist.paths.includes(`${advisory.id}|${path}`)
59-
)
53+
const isAllowListed = advisory.findings.every((finding) =>
54+
finding.paths.every((path) =>
55+
this.allowlist.paths.includes(`${advisory.id}|${path}`)
6056
)
61-
) {
57+
);
58+
59+
if (isAllowListed) {
6260
return;
6361
}
6462

6563
this.advisoriesFound.push(advisory);
6664
}
6765

6866
load(parsedOutput) {
69-
Object.values(parsedOutput.advisories).forEach((a) => this.process(a));
67+
// only for npm ver. 6
68+
if (parsedOutput.advisories) {
69+
Object.values(parsedOutput.advisories).forEach((a) => this.process(a));
70+
return this.getSummary();
71+
}
7072

73+
// only for npm ver. 7
74+
Object.keys(parsedOutput.vulnerabilities)
75+
.map((key, index) => {
76+
const vulnerability = parsedOutput.vulnerabilities[key];
77+
let { via } = vulnerability;
78+
79+
if (typeof via[0] === "string") {
80+
via = parsedOutput.vulnerabilities[via[0]].via;
81+
(via[index] || via[0]).paths = `${vulnerability.name}>${
82+
(via[index] || via[0]).name
83+
}`;
84+
}
85+
return {
86+
id: (via[index] || via[0]).source,
87+
module_name: vulnerability.name,
88+
severity: vulnerability.severity,
89+
nodes: vulnerability.nodes,
90+
findings: via.map((v) => ({ paths: [v.paths || v.name] })),
91+
};
92+
})
93+
.forEach((a) => this.process(a));
7194
return this.getSummary();
7295
}
7396

lib/common.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,25 @@ function runProgram(command, args, options, stdoutListener, stderrListener) {
7878
eventStream.mapSync((data) => {
7979
if (!data) return;
8080
try {
81+
// due to response without error
82+
if (data.message && data.message.includes("ENOTFOUND")) {
83+
stderrListener(data.message);
84+
return;
85+
}
86+
if (data.statusCode === 404) {
87+
stderrListener(data.message);
88+
return;
89+
}
90+
8191
stdoutListener(data);
8292
} catch (error) {
8393
stderrListener(error);
8494
}
8595
})
8696
);
87-
return new Promise((resolve) => {
97+
return new Promise((resolve, reject) => {
8898
proc.on("close", () => resolve());
99+
proc.on("error", (error) => reject(error));
89100
});
90101
}
91102

lib/npm-auditer.js

+19-11
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ function printReport(parsedOutput, levels, reportType) {
4040
printReportObj("NPM audit report JSON:", parsedOutput);
4141
break;
4242
case "important": {
43-
const relevantAdvisories = Object.keys(parsedOutput.advisories).reduce(
43+
const advisories =
44+
parsedOutput.auditReportVersion === 2
45+
? parsedOutput.vulnerabilities
46+
: parsedOutput.advisories;
47+
const relevantAdvisories = Object.keys(advisories).reduce(
4448
(acc, advisory) =>
45-
levels[parsedOutput.advisories[advisory].severity]
46-
? {
47-
[advisory]: parsedOutput.advisories[advisory],
48-
...acc,
49-
}
49+
levels[advisories[advisory].severity]
50+
? { [advisory]: advisories[advisory], ...acc }
5051
: acc,
5152
{}
5253
);
@@ -67,6 +68,13 @@ function printReport(parsedOutput, levels, reportType) {
6768
}
6869
}
6970

71+
function report(parsedOutput, config, reporter) {
72+
printReport(parsedOutput, config.levels, config["report-type"]);
73+
const model = new Model(config);
74+
const summary = model.load(parsedOutput);
75+
return reporter(summary, config, parsedOutput);
76+
}
77+
7078
/**
7179
* Audit your NPM project!
7280
*
@@ -86,10 +94,10 @@ async function audit(config, reporter = reportAudit) {
8694
const { code, summary } = parsedOutput.error;
8795
throw new Error(`code ${code}: ${summary}`);
8896
}
89-
printReport(parsedOutput, config.levels, config["report-type"]);
90-
const model = new Model(config);
91-
const summary = model.load(parsedOutput);
92-
return reporter(summary, config, parsedOutput);
97+
return report(parsedOutput, config, reporter);
9398
}
9499

95-
module.exports = { audit };
100+
module.exports = {
101+
audit,
102+
report,
103+
};

test/common.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
const path = require("path");
2+
const Allowlist = require("../lib/allowlist");
3+
14
function summaryWithDefault(additions = {}) {
25
const summary = {
36
allowlistedModulesFound: [],
@@ -12,4 +15,31 @@ function summaryWithDefault(additions = {}) {
1215
return { ...summary, ...additions };
1316
}
1417

15-
module.exports = { summaryWithDefault };
18+
function config(additions) {
19+
const defaultConfig = {
20+
levels: {
21+
low: false,
22+
moderate: false,
23+
high: false,
24+
critical: false,
25+
},
26+
"report-type": "important",
27+
allowlist: new Allowlist(),
28+
"show-not-found": false,
29+
"retry-count": 5,
30+
directory: "./",
31+
registry: undefined,
32+
"pass-enoaudit": false,
33+
};
34+
return { ...defaultConfig, ...additions };
35+
}
36+
37+
function testDir(s) {
38+
return path.resolve(__dirname, s);
39+
}
40+
41+
module.exports = {
42+
summaryWithDefault,
43+
config,
44+
testDir,
45+
};
+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
{
2+
"actions": [
3+
{
4+
"isMajor": false,
5+
"action": "install",
6+
"resolves": [
7+
{
8+
"id": 880,
9+
"path": "axios",
10+
"dev": false,
11+
"optional": false,
12+
"bundled": false
13+
},
14+
{
15+
"id": 1594,
16+
"path": "axios",
17+
"dev": false,
18+
"optional": false,
19+
"bundled": false
20+
}
21+
],
22+
"module": "axios",
23+
"target": "0.21.1"
24+
},
25+
{
26+
"isMajor": false,
27+
"action": "install",
28+
"resolves": [
29+
{
30+
"id": 880,
31+
"path": "github-build>axios",
32+
"dev": false,
33+
"optional": false,
34+
"bundled": false
35+
},
36+
{
37+
"id": 1594,
38+
"path": "github-build>axios",
39+
"dev": false,
40+
"optional": false,
41+
"bundled": false
42+
}
43+
],
44+
"module": "github-build",
45+
"target": "1.2.2"
46+
}
47+
],
48+
"advisories": {
49+
"880": {
50+
"findings": [
51+
{
52+
"version": "0.15.3",
53+
"paths": [
54+
"axios"
55+
]
56+
},
57+
{
58+
"version": "0.15.3",
59+
"paths": [
60+
"github-build>axios"
61+
]
62+
}
63+
],
64+
"id": 880,
65+
"created": "2019-05-06T19:14:45.155Z",
66+
"updated": "2019-06-03T17:55:10.532Z",
67+
"deleted": null,
68+
"title": "Denial of Service",
69+
"found_by": {
70+
"link": "https://nornagon.net/",
71+
"name": "Jeremy Apthorp"
72+
},
73+
"reported_by": {
74+
"link": "https://nornagon.net/",
75+
"name": "Jeremy Apthorp"
76+
},
77+
"module_name": "axios",
78+
"cves": [],
79+
"vulnerable_versions": "<0.18.1",
80+
"patched_versions": ">=0.18.1",
81+
"overview": "Versions of `axios` prior to 0.18.1 are vulnerable to Denial of Service. If a request exceeds the `maxContentLength` property, the package prints an error but does not stop the request. This may cause high CPU usage and lead to Denial of Service.",
82+
"recommendation": "Upgrade to 0.18.1 or later.",
83+
"references": "- [Github Issue](https://github.com/axios/axios/issues/1098)\n- [Snyk Report](https://snyk.io/vuln/SNYK-JS-AXIOS-174505)",
84+
"access": "public",
85+
"severity": "moderate",
86+
"cwe": "CWE-400",
87+
"metadata": {
88+
"module_type": "",
89+
"exploitability": 4,
90+
"affected_components": ""
91+
},
92+
"url": "https://npmjs.com/advisories/880"
93+
},
94+
"1594": {
95+
"findings": [
96+
{
97+
"version": "0.15.3",
98+
"paths": [
99+
"axios"
100+
]
101+
},
102+
{
103+
"version": "0.15.3",
104+
"paths": [
105+
"github-build>axios"
106+
]
107+
}
108+
],
109+
"id": 1594,
110+
"created": "2021-01-04T21:04:59.346Z",
111+
"updated": "2021-01-04T21:05:54.214Z",
112+
"deleted": null,
113+
"title": "Server-Side Request Forgery",
114+
"found_by": {
115+
"link": "",
116+
"name": "Anonymous",
117+
"email": ""
118+
},
119+
"reported_by": {
120+
"link": "",
121+
"name": "Anonymous",
122+
"email": ""
123+
},
124+
"module_name": "axios",
125+
"cves": [
126+
"CVE-2020-28168"
127+
],
128+
"vulnerable_versions": "<0.21.1",
129+
"patched_versions": ">=0.21.1",
130+
"overview": "The `axios` NPM package before 0.21.1 contains a Server-Side Request Forgery (SSRF) vulnerability where an attacker is able to bypass a proxy by providing a URL that responds with a redirect to a restricted host or IP address.",
131+
"recommendation": "Upgrade to 0.21.1 or later.",
132+
"references": "- [Github Issue](https://github.com/axios/axios/issues/3369)\n- [Fix commit](https://github.com/axios/axios/commit/c7329fefc890050edd51e40e469a154d0117fc55)\n- [GitHub Advisory](https://github.com/advisories/GHSA-4w2v-q235-vp99)\n- [Snyk Report](https://snyk.io/vuln/SNYK-JS-AXIOS-1038255)",
133+
"access": "public",
134+
"severity": "high",
135+
"cwe": "CWE-918",
136+
"metadata": {
137+
"module_type": "",
138+
"exploitability": 5,
139+
"affected_components": ""
140+
},
141+
"url": "https://npmjs.com/advisories/1594"
142+
}
143+
},
144+
"muted": [],
145+
"metadata": {
146+
"vulnerabilities": {
147+
"info": 0,
148+
"low": 0,
149+
"moderate": 2,
150+
"high": 2,
151+
"critical": 0
152+
},
153+
"dependencies": 8,
154+
"devDependencies": 0,
155+
"optionalDependencies": 0,
156+
"totalDependencies": 8
157+
},
158+
"runId": "392f2772-b277-43ce-a5a4-3351f5e082f8"
159+
}

0 commit comments

Comments
 (0)