Skip to content

Commit

Permalink
feat: add ability to exclude vulnerabilities (#133)
Browse files Browse the repository at this point in the history
Some reported vulnerabilities have no real world impact.
Add the ability to exclude these vulnerabilities
when failures are being reported.

Signed-off-by: Michael Dawson <mdawson@devrus.com>
  • Loading branch information
mhdawson authored Mar 10, 2022
1 parent 66e53ee commit 23f726d
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 8 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ Npcheck requires a configuration file where custom behavior can be specified. Th

- `citgm.skip[modules]`: Modules to be skipped by the CITGM checker _(type: Array)_

- `allow`: Config object do define vulnerabilities that have been accessed as ok to ignore. _(type: Object)_

- `allow[CVE]`: Module and effected modules that are allowed to be ignored for CVE. _(type: Array)_

- 'allow[CVE][i].name`: Name of the module against which the CVE is reported. _(type: String)_

- 'allow[CVE][i].effects: Modules that include the module againts which the CVE is reported. _(type: Array)_

### Example

A simple npcheck configuration file.
Expand All @@ -55,6 +63,14 @@ A simple npcheck configuration file.
},
"citgm": {
"skip": ["rhea"]
},
"audit": {
"allow": {
"CVE-2022-0235": [{
"name": "node-fetch",
"effects": ["opencollective"]
}]
}
}
}
```
Expand Down
31 changes: 27 additions & 4 deletions src/plugins/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ const ONE_MONTH = 30; // days

const isSourceVulnerability = (item) => item.source !== undefined;

const isVulnAllowed = (vuln, config) => {
if (config.audit && config.audit.allow && config.audit.allow[vuln.cve]) {
for (const allowed of config.audit.allow[vuln.cve]) {
if ((allowed.name === vuln.name) &&
vuln.effects &&
vuln.effects.every(elem => {
return allowed.effects.includes(elem);
})
) {
return true;
}
}
}
return false;
};

const formatAudit = (v) => ({
name: v.name,
created: v.created,
Expand All @@ -26,7 +42,7 @@ const formatOutputList = (vulnerabilities) => {
.join('\n');
};

const auditPlugin = async () => {
const auditPlugin = async (pkg, config) => {
const auditData = await getAuditInfo();
const audit = Object.keys(auditData.vulnerabilities)
.map((key) => auditData.vulnerabilities[key])
Expand Down Expand Up @@ -78,7 +94,8 @@ const auditPlugin = async () => {
const publishDate = min([new Date(v.created), new Date(v.updated)]);
return (
(v.severity === 'high' || v.severity === 'critical') &&
differenceInDays(now, publishDate) > ONE_MONTH
differenceInDays(now, publishDate) > ONE_MONTH &&
!isVulnAllowed(v, config)
);
});

Expand All @@ -102,7 +119,8 @@ const auditPlugin = async () => {
const publishDate = min([new Date(v.created), new Date(v.updated)]);
return (
v.severity === 'moderate' &&
differenceInDays(now, publishDate) > ONE_MONTH * 4
differenceInDays(now, publishDate) > ONE_MONTH * 4 &&
!isVulnAllowed(v, config)
);
});

Expand All @@ -119,7 +137,12 @@ const auditPlugin = async () => {
}

// Warn if there is more than 10 Low vulnerabilities (report the number of these)
const lowRisk = auditResult.filter((v) => v.severity === 'low');
const lowRisk = auditResult.filter((v) => {
return (
v.severity === 'low' &&
!isVulnAllowed(v, config)
);
});

if (lowRisk.length >= 10) {
const format = lowRisk.length === 1 ? 'vulnerability' : 'vulnerabilities';
Expand Down
56 changes: 52 additions & 4 deletions test/plugins/audit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ it('should return null if no vulnerabilities are found', async () => {
});
});

const result = await auditPlugin();
const result = await auditPlugin('', {});
expect(result).toBe(null);
expect(success).toHaveBeenCalled();
});
Expand Down Expand Up @@ -61,7 +61,7 @@ it('should return an error if a critical vulnerability is active for more than 1
});
});

const result = await auditPlugin();
const result = await auditPlugin('', {});
expect(result.length).toBe(1);
expect(result[0].type).toBe('error');
expect(network.fetch).toHaveBeenCalled();
Expand All @@ -71,6 +71,54 @@ it('should return an error if a critical vulnerability is active for more than 1
expect(failure).toHaveBeenCalled();
});

it('should not return an error if a critical vulnerability is active for more than 1 month but is allowed', async () => {
// mocking the NPM audit info
npm.getAuditInfo.mockImplementation(() => {
return Promise.resolve({
auditReportVersion: 2,
vulnerabilities: {
'bad-package': {
name: 'bad-package',
severity: 'critical',
via: [
{
source: 1756,
url: 'https://npmjs.com/advisories/1756'
}
],
effects: ['bad-package2']
}
}
});
});
// mocking http request
network.fetch.mockImplementation(() => {
return Promise.resolve({
id: 1756,
cves: ['CVE-2021-25945'],
created: '2021-06-08T23:17:06.692',
updated: '2021-06-08T23:17:06.692'
});
});

const result = await auditPlugin('', {
audit: {
allow: {
'CVE-2021-25945': [{
name: 'bad-package',
effects: ['bad-package2']
}]
}
}
});
expect(result).toBe(null);
expect(network.fetch).toHaveBeenCalled();
expect(network.fetch).toHaveBeenCalledWith(
'https://registry.npmjs.org/-/npm/v1/security/advisories/1756'
);
expect(success).toHaveBeenCalled();
});

it('should return a warning if a moderate vulnerability is active for more than 4 months', async () => {
// mocking the NPM audit info
npm.getAuditInfo.mockImplementation(() => {
Expand Down Expand Up @@ -100,7 +148,7 @@ it('should return a warning if a moderate vulnerability is active for more than
});
});

const result = await auditPlugin();
const result = await auditPlugin('', {});

expect(result.length).toBe(1);
expect(result[0].type).toBe('warning');
Expand Down Expand Up @@ -149,7 +197,7 @@ it("should return a warning if they're more than 10 low risk vulnerabilities", a
});
});

const result = await auditPlugin();
const result = await auditPlugin('', {});

expect(result.length).toBe(1);
expect(result[0].type).toBe('warning');
Expand Down

0 comments on commit 23f726d

Please sign in to comment.