diff --git a/src/cli/commands/protect/prompts.ts b/src/cli/commands/protect/prompts.ts index c260d65d053..d38e268509c 100644 --- a/src/cli/commands/protect/prompts.ts +++ b/src/cli/commands/protect/prompts.ts @@ -18,7 +18,8 @@ import { parsePackageString as moduleToObject } from 'snyk-module'; import * as config from '../../../lib/config'; import * as snykPolicy from 'snyk-policy'; import chalk from 'chalk'; -import { AnnotatedIssue } from '../../../lib/snyk-test/legacy'; +import { AnnotatedIssue, SEVERITY } from '../../../lib/snyk-test/legacy'; +import { titleCaseText } from '../test/formatters/legacy-format-issue'; const debug = debugModule('snyk'); @@ -42,7 +43,7 @@ function sort(prop) { }; } -function createSeverityBasedIssueHeading(msg, severity) { +function createSeverityBasedIssueHeading(msg: string, severity: SEVERITY) { // Example: ✗ Medium severity vulnerability found in xmldom const severitiesColourMapping = { low: { @@ -609,7 +610,7 @@ function generatePrompt( debug('Skipping issues in core package with no upgrade path: ' + id); } const vulnIn = vuln.from.slice(-1).pop(); - const severity = vuln.severity[0].toUpperCase() + vuln.severity.slice(1); + const severity = titleCaseText(vuln.severity); let infoLink = ' Info: ' + chalk.underline(config.ROOT); @@ -617,6 +618,13 @@ function generatePrompt( let fromText: boolean | string = false; const group = vuln.grouped && vuln.grouped.main ? vuln.grouped : false; + let originalSeverityStr = ''; + if (vuln.originalSeverity && vuln.originalSeverity !== vuln.severity) { + originalSeverityStr = ` (originally ${titleCaseText( + vuln.originalSeverity, + )})`; + } + if (group) { infoLink += chalk.underline( '/package/npm/' + group.affected.name + '/' + group.affected.version, @@ -626,7 +634,7 @@ function generatePrompt( messageIntro = fmt( '✗ %s %s %s introduced %s %s', group.count, - severity, + `${severity}${originalSeverityStr}`, issues, joiningText, group.affected.full, @@ -639,7 +647,7 @@ function generatePrompt( infoLink += chalk.underline('/vuln/' + vuln.id); messageIntro = fmt( '✗ %s severity %s found in %s, introduced via', - severity, + `${severity}${originalSeverityStr}`, vuln.type === 'license' ? 'issue' : 'vuln', vulnIn, from, diff --git a/src/cli/commands/test/formatters/legacy-format-issue.ts b/src/cli/commands/test/formatters/legacy-format-issue.ts index de7f396cf2d..e635d9a0995 100644 --- a/src/cli/commands/test/formatters/legacy-format-issue.ts +++ b/src/cli/commands/test/formatters/legacy-format-issue.ts @@ -13,6 +13,7 @@ import { GroupedVuln, AnnotatedIssue, DockerIssue, + SEVERITY, } from '../../../../lib/snyk-test/legacy'; import { formatLegalInstructions } from './legal-license-instructions'; import { getReachabilityText } from './format-reachability'; @@ -35,12 +36,13 @@ export function formatIssues( ).join(', '); const vulnOutput = { - issueHeading: createSeverityBasedIssueHeading( - vuln.metadata.severity, - vuln.metadata.type, - vuln.metadata.name, - false, - ), + issueHeading: createSeverityBasedIssueHeading({ + severity: vuln.metadata.severity, + originalSeverity: vuln.originalSeverity, + type: vuln.metadata.type, + packageName: vuln.metadata.name, + isNew: false, + }), introducedThrough: ' Introduced through: ' + uniquePackages, description: ' Description: ' + vuln.title, info: ' Info: ' + chalk.underline(config.ROOT + '/vuln/' + vulnID), @@ -76,7 +78,21 @@ export function formatIssues( ); } -function createSeverityBasedIssueHeading(severity, type, packageName, isNew) { +type CreateSeverityBasedIssueHeading = { + severity: SEVERITY; + originalSeverity?: SEVERITY; + type: string; + packageName: string; + isNew: boolean; +}; + +function createSeverityBasedIssueHeading({ + severity, + originalSeverity, + type, + packageName, + isNew, +}: CreateSeverityBasedIssueHeading) { // Example: ✗ Medium severity vulnerability found in xmldom const vulnTypeText = type === 'license' ? 'issue' : 'vulnerability'; const severitiesColourMapping = { @@ -96,11 +112,17 @@ function createSeverityBasedIssueHeading(severity, type, packageName, isNew) { }, }, }; + + let originalSeverityStr = ''; + if (originalSeverity && originalSeverity !== severity) { + originalSeverityStr = ` (originally ${titleCaseText(originalSeverity)})`; + } + return ( severitiesColourMapping[severity].colorFunc( '✗ ' + titleCaseText(severity) + - ' severity ' + + ` severity${originalSeverityStr} ` + vulnTypeText + ' found in ' + chalk.underline(packageName), diff --git a/src/cli/commands/test/formatters/remediation-based-format-issues.ts b/src/cli/commands/test/formatters/remediation-based-format-issues.ts index 842101c8179..6753cb4a66c 100644 --- a/src/cli/commands/test/formatters/remediation-based-format-issues.ts +++ b/src/cli/commands/test/formatters/remediation-based-format-issues.ts @@ -57,6 +57,7 @@ export function formatIssuesWithRemediation( const vulnData = { title: vuln.title, severity: vuln.severity, + originalSeverity: vuln.originalSeverity, isNew: vuln.isNew, name: vuln.name, type: vuln.metadata.type, @@ -175,6 +176,7 @@ function constructLicenseText( basicLicenseInfo[id].paths, testOptions, basicLicenseInfo[id].note, + undefined, // We can never override license rules, so no originalSeverity here basicLicenseInfo[id].legalInstructions, ); licenseTextArray.push('\n' + licenseText); @@ -217,6 +219,7 @@ function constructPatchesText( basicVulnInfo[id].paths, testOptions, basicVulnInfo[id].note, + basicVulnInfo[id].originalSeverity, ); patchedTextArray.push(patchedText + thisPatchFixes); } @@ -247,6 +250,7 @@ function thisUpgradeFixes( basicVulnInfo[id].paths, testOptions, basicVulnInfo[id].note, + basicVulnInfo[id].originalSeverity, [], basicVulnInfo[id].reachability, basicVulnInfo[id].sampleReachablePaths, @@ -400,6 +404,7 @@ function constructUnfixableText( issueInfo.paths, testOptions, issueInfo.note, + issueInfo.originalSeverity, [], issue.reachability, ) + `${extraInfo}`, @@ -428,6 +433,7 @@ export function formatIssue( paths: string[][], testOptions: TestOptions, note: string | false, + originalSeverity?: SEVERITY, legalInstructions?: LegalInstruction[], reachability?: REACHABILITY, sampleReachablePaths?: SampleReachablePaths, @@ -493,11 +499,16 @@ export function formatIssue( reachablePathsTemplate, ); + let originalSeverityStr = ''; + if (originalSeverity && originalSeverity !== severity) { + originalSeverityStr = ` (originally ${titleCaseText(originalSeverity)})`; + } + return ( severitiesColourMapping[severity].colorFunc( ` ✗ ${chalk.bold(title)}${newBadge} [${titleCaseText( severity, - )} Severity]`, + )} Severity${originalSeverityStr}]`, ) + reachabilityText + `[${config.ROOT}/vuln/${id}]` + diff --git a/src/cli/commands/test/formatters/types.ts b/src/cli/commands/test/formatters/types.ts index dc19c2b23f4..cadf620cefd 100644 --- a/src/cli/commands/test/formatters/types.ts +++ b/src/cli/commands/test/formatters/types.ts @@ -14,6 +14,7 @@ export interface BasicVulnInfo { type: string; title: string; severity: SEVERITY; + originalSeverity?: SEVERITY; isNew: boolean; name: string; version: string; diff --git a/src/cli/commands/test/index.ts b/src/cli/commands/test/index.ts index f97a13792e3..34f142b9bbf 100644 --- a/src/cli/commands/test/index.ts +++ b/src/cli/commands/test/index.ts @@ -651,6 +651,7 @@ function groupVulnerabilities(vulns): GroupedVuln[] { map[curr.id].title = curr.title; map[curr.id].note = curr.note; map[curr.id].severity = curr.severity as SEVERITY; + map[curr.id].originalSeverity = curr.originalSeverity as SEVERITY; map[curr.id].isNew = isNewVuln(curr); map[curr.id].name = curr.name; map[curr.id].version = curr.version; diff --git a/src/lib/snyk-test/legacy.ts b/src/lib/snyk-test/legacy.ts index 25387396413..37933a47e34 100644 --- a/src/lib/snyk-test/legacy.ts +++ b/src/lib/snyk-test/legacy.ts @@ -50,6 +50,7 @@ export interface GroupedVuln { title: string; note: string | false; severity: SEVERITY; + originalSeverity?: SEVERITY; isNew: boolean; name: string; version: string; @@ -107,6 +108,7 @@ interface AnnotatedIssue extends IssueData { isUpgradable: boolean; isPatchable: boolean; severity: SEVERITY; + originalSeverity?: SEVERITY; // These fields present for "node_module" based scans to allow remediation bundled?: any; diff --git a/test/acceptance/display-test-results.test.ts b/test/acceptance/display-test-results.test.ts index 162b6990e2c..8a60e3e2a5d 100644 --- a/test/acceptance/display-test-results.test.ts +++ b/test/acceptance/display-test-results.test.ts @@ -2,13 +2,15 @@ import * as tap from 'tap'; import * as sinon from 'sinon'; import * as fs from 'fs'; -// tslint:disable-next-line:no-var-requires -const snykTest = require('../../src/cli/commands/test'); +import * as config from '../../src/lib/config'; +import * as url from 'url'; +import * as cli from '../../src/cli/commands'; import * as snyk from '../../src/lib'; import { chdirWorkspaces } from './workspace-helper'; const { test } = tap; (tap as any).runOnly = false; // <- for debug. set to true, and replace a test to only(..) +const apiUrl = url.parse(config.API); test('`test ruby-app` remediation displayed', async (t) => { chdirWorkspaces(); @@ -21,7 +23,7 @@ test('`test ruby-app` remediation displayed', async (t) => { ); const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); try { - await snykTest('ruby-app'); + await cli.test('ruby-app'); } catch (error) { const res = error.message; t.match( @@ -57,7 +59,7 @@ test('`test ruby-app` legal instructions displayed', async (t) => { ); const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); try { - await snykTest('ruby-app'); + await cli.test('ruby-app'); } catch (error) { const res = error.message; t.match(res, 'I am legal license instruction'); @@ -78,7 +80,7 @@ test('`test pip-app-license-issue` legal instructions displayed (legacy formatte ); const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); try { - await snykTest('pip-app-license-issue'); + await cli.test('pip-app-license-issue'); } catch (error) { const res = error.message; t.match(res, 'I am legal license instruction'); @@ -99,7 +101,7 @@ test('test reachability info is displayed', async (t) => { ); const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); try { - await snykTest('maven-app', { + await cli.test('maven-app', { reachableVulns: true, }); } catch (error) { @@ -114,3 +116,129 @@ test('test reachability info is displayed', async (t) => { snykTestStub.restore(); t.end(); }); + +test('`test npm-package-with-severity-override` show original severity upgrade', async (t) => { + chdirWorkspaces(); + const stubbedResponse = JSON.parse( + fs.readFileSync( + __dirname + + '/fixtures/npm-package-with-severity-override/test-graph-result-upgrade.json', + 'utf8', + ), + ); + + const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); + try { + await cli.test('npm-package-with-severity-override'); + } catch (error) { + const { message } = error; + t.match( + message, + `[Low Severity (originally Medium)][${apiUrl.protocol}//${apiUrl.host}/vuln/npm:node-uuid:20160328]`, + ); + } + + snykTestStub.restore(); + t.end(); +}); + +test('`test npm-package-with-severity-override` show original severity patches', async (t) => { + chdirWorkspaces(); + const stubbedResponse = JSON.parse( + fs.readFileSync( + __dirname + + '/fixtures/npm-package-with-severity-override/test-graph-result-patches.json', + 'utf8', + ), + ); + + const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); + try { + await cli.test('npm-package-with-severity-override'); + } catch (error) { + const { message } = error; + t.match(message, 'Patch available for node-uuid@1.4.0'); + t.match( + message, + `[Low Severity (originally Medium)][${apiUrl.protocol}//${apiUrl.host}/vuln/npm:node-uuid:20160328]`, + ); + } + + snykTestStub.restore(); + t.end(); +}); + +test('`test npm-package-with-severity-override` show original severity no remediation', async (t) => { + chdirWorkspaces(); + const stubbedResponse = JSON.parse( + fs.readFileSync( + __dirname + + '/fixtures/npm-package-with-severity-override/test-graph-result-no-remediation.json', + 'utf8', + ), + ); + + const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); + try { + await cli.test('npm-package-with-severity-override'); + } catch (error) { + const { message } = error; + t.match( + message, + `Low severity (originally Medium) vulnerability found in node-uuid`, + ); + } + + snykTestStub.restore(); + t.end(); +}); + +test('`test npm-package-with-severity-override` show original severity unresolved', async (t) => { + chdirWorkspaces(); + const stubbedResponse = JSON.parse( + fs.readFileSync( + __dirname + + '/fixtures/npm-package-with-severity-override/test-graph-result-unresolved.json', + 'utf8', + ), + ); + + const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); + try { + await cli.test('npm-package-with-severity-override'); + } catch (error) { + const { message } = error; + t.match( + message, + `Malicious Package [Low Severity (originally Medium)][${apiUrl.protocol}//${apiUrl.host}/vuln/npm:node-uuid:20160328`, + ); + } + + snykTestStub.restore(); + t.end(); +}); + +test('`test npm-package-with-severity-override` dont show original severity if its the same as original severity', async (t) => { + chdirWorkspaces(); + const stubbedResponse = JSON.parse( + fs.readFileSync( + __dirname + + '/fixtures/npm-package-with-severity-override/test-graph-result-same-severity.json', + 'utf8', + ), + ); + + const snykTestStub = sinon.stub(snyk, 'test').returns(stubbedResponse); + try { + await cli.test('npm-package-with-severity-override'); + } catch (error) { + const { message } = error; + t.match( + message, + `[Low Severity][${apiUrl.protocol}//${apiUrl.host}/vuln/npm:node-uuid:20160328]`, + ); + } + + snykTestStub.restore(); + t.end(); +}); diff --git a/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-no-remediation.json b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-no-remediation.json new file mode 100644 index 00000000000..2d60845c6a3 --- /dev/null +++ b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-no-remediation.json @@ -0,0 +1,412 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": ["1.4.4"], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [ + { + "comments": [], + "id": "patch:npm:node-uuid:20160328:0", + "modificationTime": "2019-12-03T11:40:45.815314Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" + ], + "version": "<=1.4.3 >=1.4.2" + } + ], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { + "vulnerable": ["<1.4.4"] + }, + "severity": "low", + "title": "Insecure Randomness", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "node-uuid@1.4.0"], + "upgradePath": [false, "node-uuid@1.4.6"], + "isUpgradable": true, + "isPatchable": false, + "name": "node-uuid", + "version": "1.4.0" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10019"], + "creationTime": "2014-08-06T06:10:22Z", + "credit": ["Dustin Shiver"], + "cvssScore": 7.5, + "description": "## Overview\n\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\n\nAffected versions of this package are vulnerable to Denial of Service (DoS).\nDuring parsing, the `qs` module may create a sparse area (an array where no elements are filled), and grow that array to the necessary size based on the indices used on it. An attacker can specify a high index value in a query string, thus making the server allocate a respectively big array. Truly large values can cause the server to run out of memory and cause it to crash - thus enabling a Denial-of-Service attack.\n\n## Remediation\n\nUpgrade `qs` to version 1.0.0 or higher.\n\n\n## Details\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.\r\n\r\nUnlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.\r\n\r\nOne popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.\r\n\r\nWhen it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.\r\n\r\nTwo common types of DoS vulnerabilities:\r\n\r\n* High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, [commons-fileupload:commons-fileupload](SNYK-JAVA-COMMONSFILEUPLOAD-30082).\r\n\r\n* Crash - An attacker sending crafted requests that could cause the system to crash. For Example, [npm `ws` package](npm:ws:20171108)\n\n## References\n\n- [GitHub Commit](https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8)\n\n- [GitHub Issue](https://github.com/visionmedia/node-querystring/issues/104)\n\n- [NVD](https://nvd.nist.gov/vuln/detail/CVE-2014-7191)\n", + "disclosureTime": "2014-08-06T06:10:22Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "id": "npm:qs:20140806", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10019"], + "CVE": ["CVE-2014-7191"], + "CWE": ["CWE-400"], + "GHSA": ["GHSA-gqgv-6jq5-jjj9"], + "NSP": [29] + }, + "language": "js", + "modificationTime": "2019-02-18T08:28:59.375824Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806:1", + "modificationTime": "2019-12-03T11:40:45.728930Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_1_snyk_npm.patch" + ], + "version": "=0.5.6" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806:0", + "modificationTime": "2019-12-03T11:40:45.741062Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_0_43a604b7847e56bba49d0ce3e222fe89569354d8_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:22Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/visionmedia/node-querystring/issues/104" + }, + { + "title": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2014-7191" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10020"], + "creationTime": "2014-08-06T06:10:23Z", + "credit": ["Tom Steele"], + "cvssScore": 6.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Denial of Service (DoS). When parsing a string representing a deeply nested object, qs will block the event loop for long periods of time. Such a delay may hold up the server's resources, keeping it from processing other requests in the meantime, thus enabling a Denial-of-Service attack.\n\n## Details\n\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.\n\nThe Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.\n\nLet’s take the following regular expression as an example:\n```js\nregex = /A(B|C+)+D/\n```\n\nThis regular expression accomplishes the following:\n- `A` The string must start with the letter 'A'\n- `(B|C+)+` The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the `+` matches one or more times). The `+` at the end of this section states that we can look for one or more matches of this section.\n- `D` Finally, we ensure this section of the string ends with a 'D'\n\nThe expression would match inputs such as `ABBD`, `ABCCCCD`, `ABCBCCCD` and `ACCCCCD`\n\nIt most cases, it doesn't take very long for a regex engine to find a match:\n\n```bash\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD\")'\n0.04s user 0.01s system 95% cpu 0.052 total\n\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX\")'\n1.79s user 0.02s system 99% cpu 1.812 total\n```\n\nThe entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.\n\nMost Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as _catastrophic backtracking_.\n\nLet's look at how our expression runs into this problem, using a shorter string: \"ACCCX\". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:\n1. CCC\n2. CC+C\n3. C+CC\n4. C+C+C.\n\nThe engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use [RegEx 101 debugger](https://regex101.com/debugger) to see the engine has to take a total of 38 steps before it can determine the string doesn't match.\n\nFrom there, the number of steps the engine must use to validate a string just continues to grow.\n\n| String | Number of C's | Number of steps |\n| -------|-------------:| -----:|\n| ACCCX | 3 | 38\n| ACCCCX | 4 | 71\n| ACCCCCX | 5 | 136\n| ACCCCCCCCCCCCCCX | 14 | 65,553\n\n\nBy the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.\n\n## Remediation\nUpgrade `qs` to version 1.0.0 or higher.\n## References\n- [Node Security Advisory](https://nodesecurity.io/advisories/28)\n", + "disclosureTime": "2014-08-06T06:10:23Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [], + "functions_new": [], + "id": "npm:qs:20140806-1", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10020"], + "CVE": ["CVE-2014-10064"], + "CWE": ["CWE-400"], + "NSP": [28] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:44.334026Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806-1:0", + "modificationTime": "2019-12-03T11:40:45.742148Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_0_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806-1:1", + "modificationTime": "2019-12-03T11:40:45.744535Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_1_snyk.patch" + ], + "version": "=0.5.6" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:23Z", + "references": [ + { + "title": "Node Security Advisory", + "url": "https://nodesecurity.io/advisories/28" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10407"], + "creationTime": "2017-02-14T11:44:54.163000Z", + "credit": ["Snyk Security Research Team"], + "cvssScore": 7.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Prototype Override Protection Bypass. By default `qs` protects against attacks that attempt to overwrite an object's existing prototype properties, such as `toString()`, `hasOwnProperty()`,etc.\r\n\r\nFrom [`qs` documentation](https://github.com/ljharb/qs):\r\n> By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use plainObjects as mentioned above, or set allowPrototypes to true which will allow user input to overwrite those properties. WARNING It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.\r\n\r\nOverwriting these properties can impact application logic, potentially allowing attackers to work around security controls, modify data, make the application unstable and more.\r\n\r\nIn versions of the package affected by this vulnerability, it is possible to circumvent this protection and overwrite prototype properties and functions by prefixing the name of the parameter with `[` or `]`. e.g. `qs.parse(\"]=toString\")` will return `{toString = true}`, as a result, calling `toString()` on the object will throw an exception.\r\n\r\n**Example:**\r\n```js\r\nqs.parse('toString=foo', { allowPrototypes: false })\r\n// {}\r\n\r\nqs.parse(\"]=toString\", { allowPrototypes: false })\r\n// {toString = true} <== prototype overwritten\r\n```\r\n\r\nFor more information, you can check out our [blog](https://snyk.io/blog/high-severity-vulnerability-qs/).\r\n\r\n## Disclosure Timeline\r\n- February 13th, 2017 - Reported the issue to package owner.\r\n- February 13th, 2017 - Issue acknowledged by package owner.\r\n- February 16th, 2017 - Partial fix released in versions `6.0.3`, `6.1.1`, `6.2.2`, `6.3.1`.\r\n- March 6th, 2017 - Final fix released in versions `6.4.0`,`6.3.2`, `6.2.3`, `6.1.2` and `6.0.4`\n## Remediation\nUpgrade `qs` to version 6.0.4, 6.1.2, 6.2.3, 6.3.2 or higher.\n## References\n- [GitHub Commit](https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d)\n- [GitHub Issue](https://github.com/ljharb/qs/issues/200)\n", + "disclosureTime": "2017-02-13T00:00:00Z", + "exploit": "Not Defined", + "fixedIn": ["6.0.4", "6.1.2", "6.2.3", "6.3.2"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "id": "npm:qs:20170213", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10407"], + "CVE": ["CVE-2017-1000048"], + "CWE": ["CWE-20"] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:53.880024Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20170213:0", + "modificationTime": "2019-12-03T11:40:45.855245Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/630_632.patch" + ], + "version": "=6.3.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:1", + "modificationTime": "2019-12-03T11:40:45.856271Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/631_632.patch" + ], + "version": "=6.3.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:2", + "modificationTime": "2019-12-03T11:40:45.857318Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/621_623.patch" + ], + "version": "=6.2.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:3", + "modificationTime": "2019-12-03T11:40:45.858334Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/622_623.patch" + ], + "version": "=6.2.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:4", + "modificationTime": "2019-12-03T11:40:45.859411Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/610_612.patch" + ], + "version": "=6.1.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:5", + "modificationTime": "2019-12-03T11:40:45.860523Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/611_612.patch" + ], + "version": "=6.1.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:6", + "modificationTime": "2019-12-03T11:40:45.861504Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/602_604.patch" + ], + "version": "=6.0.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:7", + "modificationTime": "2019-12-03T11:40:45.862615Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/603_604.patch" + ], + "version": "=6.0.3" + } + ], + "proprietary": true, + "publicationTime": "2017-03-01T10:00:54Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/ljharb/qs/issues/200" + } + ], + "semver": { + "vulnerable": [ + "<6.0.4", + ">=6.1.0 <6.1.2", + ">=6.2.0 <6.2.3", + ">=6.3.0 <6.3.2" + ] + }, + "severity": "low", + "title": "Prototype Override Protection Bypass", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@6.0.4"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + } + ], + "ok": false, + "dependencyCount": 2, + "org": "another-org", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": null, + "packageManager": "npm", + "ignoreSettings": null, + "summary": "4 vulnerable dependency paths", + "filesystemPolicy": false, + "filtered": { + "ignore": [], + "patch": [] + }, + "uniqueCount": 4, + "projectName": "shallow-goof", + "displayTargetFile": "package-lock.json" +} diff --git a/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-patches.json b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-patches.json new file mode 100644 index 00000000000..acef355696c --- /dev/null +++ b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-patches.json @@ -0,0 +1,429 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": ["1.4.4"], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [ + { + "comments": [], + "id": "patch:npm:node-uuid:20160328:0", + "modificationTime": "2019-12-03T11:40:45.815314Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" + ], + "version": "<=1.4.3 >=1.4.2" + } + ], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { + "vulnerable": ["<1.4.4"] + }, + "severity": "low", + "title": "Insecure Randomness", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "node-uuid@1.4.0"], + "upgradePath": [false, "node-uuid@1.4.6"], + "isUpgradable": true, + "isPatchable": false, + "name": "node-uuid", + "version": "1.4.0" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10019"], + "creationTime": "2014-08-06T06:10:22Z", + "credit": ["Dustin Shiver"], + "cvssScore": 7.5, + "description": "## Overview\n\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\n\nAffected versions of this package are vulnerable to Denial of Service (DoS).\nDuring parsing, the `qs` module may create a sparse area (an array where no elements are filled), and grow that array to the necessary size based on the indices used on it. An attacker can specify a high index value in a query string, thus making the server allocate a respectively big array. Truly large values can cause the server to run out of memory and cause it to crash - thus enabling a Denial-of-Service attack.\n\n## Remediation\n\nUpgrade `qs` to version 1.0.0 or higher.\n\n\n## Details\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.\r\n\r\nUnlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.\r\n\r\nOne popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.\r\n\r\nWhen it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.\r\n\r\nTwo common types of DoS vulnerabilities:\r\n\r\n* High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, [commons-fileupload:commons-fileupload](SNYK-JAVA-COMMONSFILEUPLOAD-30082).\r\n\r\n* Crash - An attacker sending crafted requests that could cause the system to crash. For Example, [npm `ws` package](npm:ws:20171108)\n\n## References\n\n- [GitHub Commit](https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8)\n\n- [GitHub Issue](https://github.com/visionmedia/node-querystring/issues/104)\n\n- [NVD](https://nvd.nist.gov/vuln/detail/CVE-2014-7191)\n", + "disclosureTime": "2014-08-06T06:10:22Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "id": "npm:qs:20140806", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10019"], + "CVE": ["CVE-2014-7191"], + "CWE": ["CWE-400"], + "GHSA": ["GHSA-gqgv-6jq5-jjj9"], + "NSP": [29] + }, + "language": "js", + "modificationTime": "2019-02-18T08:28:59.375824Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806:1", + "modificationTime": "2019-12-03T11:40:45.728930Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_1_snyk_npm.patch" + ], + "version": "=0.5.6" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806:0", + "modificationTime": "2019-12-03T11:40:45.741062Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_0_43a604b7847e56bba49d0ce3e222fe89569354d8_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:22Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/visionmedia/node-querystring/issues/104" + }, + { + "title": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2014-7191" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10020"], + "creationTime": "2014-08-06T06:10:23Z", + "credit": ["Tom Steele"], + "cvssScore": 6.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Denial of Service (DoS). When parsing a string representing a deeply nested object, qs will block the event loop for long periods of time. Such a delay may hold up the server's resources, keeping it from processing other requests in the meantime, thus enabling a Denial-of-Service attack.\n\n## Details\n\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.\n\nThe Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.\n\nLet’s take the following regular expression as an example:\n```js\nregex = /A(B|C+)+D/\n```\n\nThis regular expression accomplishes the following:\n- `A` The string must start with the letter 'A'\n- `(B|C+)+` The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the `+` matches one or more times). The `+` at the end of this section states that we can look for one or more matches of this section.\n- `D` Finally, we ensure this section of the string ends with a 'D'\n\nThe expression would match inputs such as `ABBD`, `ABCCCCD`, `ABCBCCCD` and `ACCCCCD`\n\nIt most cases, it doesn't take very long for a regex engine to find a match:\n\n```bash\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD\")'\n0.04s user 0.01s system 95% cpu 0.052 total\n\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX\")'\n1.79s user 0.02s system 99% cpu 1.812 total\n```\n\nThe entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.\n\nMost Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as _catastrophic backtracking_.\n\nLet's look at how our expression runs into this problem, using a shorter string: \"ACCCX\". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:\n1. CCC\n2. CC+C\n3. C+CC\n4. C+C+C.\n\nThe engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use [RegEx 101 debugger](https://regex101.com/debugger) to see the engine has to take a total of 38 steps before it can determine the string doesn't match.\n\nFrom there, the number of steps the engine must use to validate a string just continues to grow.\n\n| String | Number of C's | Number of steps |\n| -------|-------------:| -----:|\n| ACCCX | 3 | 38\n| ACCCCX | 4 | 71\n| ACCCCCX | 5 | 136\n| ACCCCCCCCCCCCCCX | 14 | 65,553\n\n\nBy the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.\n\n## Remediation\nUpgrade `qs` to version 1.0.0 or higher.\n## References\n- [Node Security Advisory](https://nodesecurity.io/advisories/28)\n", + "disclosureTime": "2014-08-06T06:10:23Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [], + "functions_new": [], + "id": "npm:qs:20140806-1", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10020"], + "CVE": ["CVE-2014-10064"], + "CWE": ["CWE-400"], + "NSP": [28] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:44.334026Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806-1:0", + "modificationTime": "2019-12-03T11:40:45.742148Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_0_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806-1:1", + "modificationTime": "2019-12-03T11:40:45.744535Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_1_snyk.patch" + ], + "version": "=0.5.6" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:23Z", + "references": [ + { + "title": "Node Security Advisory", + "url": "https://nodesecurity.io/advisories/28" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10407"], + "creationTime": "2017-02-14T11:44:54.163000Z", + "credit": ["Snyk Security Research Team"], + "cvssScore": 7.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Prototype Override Protection Bypass. By default `qs` protects against attacks that attempt to overwrite an object's existing prototype properties, such as `toString()`, `hasOwnProperty()`,etc.\r\n\r\nFrom [`qs` documentation](https://github.com/ljharb/qs):\r\n> By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use plainObjects as mentioned above, or set allowPrototypes to true which will allow user input to overwrite those properties. WARNING It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.\r\n\r\nOverwriting these properties can impact application logic, potentially allowing attackers to work around security controls, modify data, make the application unstable and more.\r\n\r\nIn versions of the package affected by this vulnerability, it is possible to circumvent this protection and overwrite prototype properties and functions by prefixing the name of the parameter with `[` or `]`. e.g. `qs.parse(\"]=toString\")` will return `{toString = true}`, as a result, calling `toString()` on the object will throw an exception.\r\n\r\n**Example:**\r\n```js\r\nqs.parse('toString=foo', { allowPrototypes: false })\r\n// {}\r\n\r\nqs.parse(\"]=toString\", { allowPrototypes: false })\r\n// {toString = true} <== prototype overwritten\r\n```\r\n\r\nFor more information, you can check out our [blog](https://snyk.io/blog/high-severity-vulnerability-qs/).\r\n\r\n## Disclosure Timeline\r\n- February 13th, 2017 - Reported the issue to package owner.\r\n- February 13th, 2017 - Issue acknowledged by package owner.\r\n- February 16th, 2017 - Partial fix released in versions `6.0.3`, `6.1.1`, `6.2.2`, `6.3.1`.\r\n- March 6th, 2017 - Final fix released in versions `6.4.0`,`6.3.2`, `6.2.3`, `6.1.2` and `6.0.4`\n## Remediation\nUpgrade `qs` to version 6.0.4, 6.1.2, 6.2.3, 6.3.2 or higher.\n## References\n- [GitHub Commit](https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d)\n- [GitHub Issue](https://github.com/ljharb/qs/issues/200)\n", + "disclosureTime": "2017-02-13T00:00:00Z", + "exploit": "Not Defined", + "fixedIn": ["6.0.4", "6.1.2", "6.2.3", "6.3.2"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "id": "npm:qs:20170213", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10407"], + "CVE": ["CVE-2017-1000048"], + "CWE": ["CWE-20"] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:53.880024Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20170213:0", + "modificationTime": "2019-12-03T11:40:45.855245Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/630_632.patch" + ], + "version": "=6.3.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:1", + "modificationTime": "2019-12-03T11:40:45.856271Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/631_632.patch" + ], + "version": "=6.3.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:2", + "modificationTime": "2019-12-03T11:40:45.857318Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/621_623.patch" + ], + "version": "=6.2.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:3", + "modificationTime": "2019-12-03T11:40:45.858334Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/622_623.patch" + ], + "version": "=6.2.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:4", + "modificationTime": "2019-12-03T11:40:45.859411Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/610_612.patch" + ], + "version": "=6.1.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:5", + "modificationTime": "2019-12-03T11:40:45.860523Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/611_612.patch" + ], + "version": "=6.1.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:6", + "modificationTime": "2019-12-03T11:40:45.861504Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/602_604.patch" + ], + "version": "=6.0.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:7", + "modificationTime": "2019-12-03T11:40:45.862615Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/603_604.patch" + ], + "version": "=6.0.3" + } + ], + "proprietary": true, + "publicationTime": "2017-03-01T10:00:54Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/ljharb/qs/issues/200" + } + ], + "semver": { + "vulnerable": [ + "<6.0.4", + ">=6.1.0 <6.1.2", + ">=6.2.0 <6.2.3", + ">=6.3.0 <6.3.2" + ] + }, + "severity": "low", + "title": "Prototype Override Protection Bypass", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@6.0.4"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + } + ], + "ok": false, + "dependencyCount": 2, + "org": "another-org", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": null, + "packageManager": "npm", + "ignoreSettings": null, + "summary": "4 vulnerable dependency paths", + "remediation": { + "unresolved": [], + "upgrade": { + "qs@0.0.6": { + "upgradeTo": "qs@6.0.4", + "upgrades": ["qs@0.0.6", "qs@0.0.6", "qs@0.0.6"], + "vulns": ["npm:qs:20170213", "npm:qs:20140806", "npm:qs:20140806-1"] + } + }, + "patch": { + "npm:node-uuid:20160328": { + "paths": [{ "ms": { "patched": "2019-11-29T15:08:55.159Z" } }] + } + }, + "ignore": {}, + "pin": {} + }, + "filesystemPolicy": false, + "filtered": { + "ignore": [], + "patch": [] + }, + "uniqueCount": 4, + "projectName": "shallow-goof", + "displayTargetFile": "package-lock.json" +} diff --git a/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-same-severity.json b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-same-severity.json new file mode 100644 index 00000000000..2387ab3709c --- /dev/null +++ b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-same-severity.json @@ -0,0 +1,430 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": ["1.4.4"], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [ + { + "comments": [], + "id": "patch:npm:node-uuid:20160328:0", + "modificationTime": "2019-12-03T11:40:45.815314Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" + ], + "version": "<=1.4.3 >=1.4.2" + } + ], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { + "vulnerable": ["<1.4.4"] + }, + "severity": "low", + "title": "Insecure Randomness", + "originalSeverity": "low", + "from": ["shallow-goof@0.0.1", "node-uuid@1.4.0"], + "upgradePath": [false, "node-uuid@1.4.6"], + "isUpgradable": true, + "isPatchable": false, + "name": "node-uuid", + "version": "1.4.0" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10019"], + "creationTime": "2014-08-06T06:10:22Z", + "credit": ["Dustin Shiver"], + "cvssScore": 7.5, + "description": "## Overview\n\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\n\nAffected versions of this package are vulnerable to Denial of Service (DoS).\nDuring parsing, the `qs` module may create a sparse area (an array where no elements are filled), and grow that array to the necessary size based on the indices used on it. An attacker can specify a high index value in a query string, thus making the server allocate a respectively big array. Truly large values can cause the server to run out of memory and cause it to crash - thus enabling a Denial-of-Service attack.\n\n## Remediation\n\nUpgrade `qs` to version 1.0.0 or higher.\n\n\n## Details\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.\r\n\r\nUnlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.\r\n\r\nOne popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.\r\n\r\nWhen it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.\r\n\r\nTwo common types of DoS vulnerabilities:\r\n\r\n* High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, [commons-fileupload:commons-fileupload](SNYK-JAVA-COMMONSFILEUPLOAD-30082).\r\n\r\n* Crash - An attacker sending crafted requests that could cause the system to crash. For Example, [npm `ws` package](npm:ws:20171108)\n\n## References\n\n- [GitHub Commit](https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8)\n\n- [GitHub Issue](https://github.com/visionmedia/node-querystring/issues/104)\n\n- [NVD](https://nvd.nist.gov/vuln/detail/CVE-2014-7191)\n", + "disclosureTime": "2014-08-06T06:10:22Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "id": "npm:qs:20140806", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10019"], + "CVE": ["CVE-2014-7191"], + "CWE": ["CWE-400"], + "GHSA": ["GHSA-gqgv-6jq5-jjj9"], + "NSP": [29] + }, + "language": "js", + "modificationTime": "2019-02-18T08:28:59.375824Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806:1", + "modificationTime": "2019-12-03T11:40:45.728930Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_1_snyk_npm.patch" + ], + "version": "=0.5.6" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806:0", + "modificationTime": "2019-12-03T11:40:45.741062Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_0_43a604b7847e56bba49d0ce3e222fe89569354d8_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:22Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/visionmedia/node-querystring/issues/104" + }, + { + "title": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2014-7191" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10020"], + "creationTime": "2014-08-06T06:10:23Z", + "credit": ["Tom Steele"], + "cvssScore": 6.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Denial of Service (DoS). When parsing a string representing a deeply nested object, qs will block the event loop for long periods of time. Such a delay may hold up the server's resources, keeping it from processing other requests in the meantime, thus enabling a Denial-of-Service attack.\n\n## Details\n\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.\n\nThe Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.\n\nLet’s take the following regular expression as an example:\n```js\nregex = /A(B|C+)+D/\n```\n\nThis regular expression accomplishes the following:\n- `A` The string must start with the letter 'A'\n- `(B|C+)+` The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the `+` matches one or more times). The `+` at the end of this section states that we can look for one or more matches of this section.\n- `D` Finally, we ensure this section of the string ends with a 'D'\n\nThe expression would match inputs such as `ABBD`, `ABCCCCD`, `ABCBCCCD` and `ACCCCCD`\n\nIt most cases, it doesn't take very long for a regex engine to find a match:\n\n```bash\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD\")'\n0.04s user 0.01s system 95% cpu 0.052 total\n\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX\")'\n1.79s user 0.02s system 99% cpu 1.812 total\n```\n\nThe entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.\n\nMost Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as _catastrophic backtracking_.\n\nLet's look at how our expression runs into this problem, using a shorter string: \"ACCCX\". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:\n1. CCC\n2. CC+C\n3. C+CC\n4. C+C+C.\n\nThe engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use [RegEx 101 debugger](https://regex101.com/debugger) to see the engine has to take a total of 38 steps before it can determine the string doesn't match.\n\nFrom there, the number of steps the engine must use to validate a string just continues to grow.\n\n| String | Number of C's | Number of steps |\n| -------|-------------:| -----:|\n| ACCCX | 3 | 38\n| ACCCCX | 4 | 71\n| ACCCCCX | 5 | 136\n| ACCCCCCCCCCCCCCX | 14 | 65,553\n\n\nBy the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.\n\n## Remediation\nUpgrade `qs` to version 1.0.0 or higher.\n## References\n- [Node Security Advisory](https://nodesecurity.io/advisories/28)\n", + "disclosureTime": "2014-08-06T06:10:23Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [], + "functions_new": [], + "id": "npm:qs:20140806-1", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10020"], + "CVE": ["CVE-2014-10064"], + "CWE": ["CWE-400"], + "NSP": [28] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:44.334026Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806-1:0", + "modificationTime": "2019-12-03T11:40:45.742148Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_0_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806-1:1", + "modificationTime": "2019-12-03T11:40:45.744535Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_1_snyk.patch" + ], + "version": "=0.5.6" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:23Z", + "references": [ + { + "title": "Node Security Advisory", + "url": "https://nodesecurity.io/advisories/28" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10407"], + "creationTime": "2017-02-14T11:44:54.163000Z", + "credit": ["Snyk Security Research Team"], + "cvssScore": 7.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Prototype Override Protection Bypass. By default `qs` protects against attacks that attempt to overwrite an object's existing prototype properties, such as `toString()`, `hasOwnProperty()`,etc.\r\n\r\nFrom [`qs` documentation](https://github.com/ljharb/qs):\r\n> By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use plainObjects as mentioned above, or set allowPrototypes to true which will allow user input to overwrite those properties. WARNING It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.\r\n\r\nOverwriting these properties can impact application logic, potentially allowing attackers to work around security controls, modify data, make the application unstable and more.\r\n\r\nIn versions of the package affected by this vulnerability, it is possible to circumvent this protection and overwrite prototype properties and functions by prefixing the name of the parameter with `[` or `]`. e.g. `qs.parse(\"]=toString\")` will return `{toString = true}`, as a result, calling `toString()` on the object will throw an exception.\r\n\r\n**Example:**\r\n```js\r\nqs.parse('toString=foo', { allowPrototypes: false })\r\n// {}\r\n\r\nqs.parse(\"]=toString\", { allowPrototypes: false })\r\n// {toString = true} <== prototype overwritten\r\n```\r\n\r\nFor more information, you can check out our [blog](https://snyk.io/blog/high-severity-vulnerability-qs/).\r\n\r\n## Disclosure Timeline\r\n- February 13th, 2017 - Reported the issue to package owner.\r\n- February 13th, 2017 - Issue acknowledged by package owner.\r\n- February 16th, 2017 - Partial fix released in versions `6.0.3`, `6.1.1`, `6.2.2`, `6.3.1`.\r\n- March 6th, 2017 - Final fix released in versions `6.4.0`,`6.3.2`, `6.2.3`, `6.1.2` and `6.0.4`\n## Remediation\nUpgrade `qs` to version 6.0.4, 6.1.2, 6.2.3, 6.3.2 or higher.\n## References\n- [GitHub Commit](https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d)\n- [GitHub Issue](https://github.com/ljharb/qs/issues/200)\n", + "disclosureTime": "2017-02-13T00:00:00Z", + "exploit": "Not Defined", + "fixedIn": ["6.0.4", "6.1.2", "6.2.3", "6.3.2"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "id": "npm:qs:20170213", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10407"], + "CVE": ["CVE-2017-1000048"], + "CWE": ["CWE-20"] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:53.880024Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20170213:0", + "modificationTime": "2019-12-03T11:40:45.855245Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/630_632.patch" + ], + "version": "=6.3.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:1", + "modificationTime": "2019-12-03T11:40:45.856271Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/631_632.patch" + ], + "version": "=6.3.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:2", + "modificationTime": "2019-12-03T11:40:45.857318Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/621_623.patch" + ], + "version": "=6.2.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:3", + "modificationTime": "2019-12-03T11:40:45.858334Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/622_623.patch" + ], + "version": "=6.2.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:4", + "modificationTime": "2019-12-03T11:40:45.859411Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/610_612.patch" + ], + "version": "=6.1.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:5", + "modificationTime": "2019-12-03T11:40:45.860523Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/611_612.patch" + ], + "version": "=6.1.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:6", + "modificationTime": "2019-12-03T11:40:45.861504Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/602_604.patch" + ], + "version": "=6.0.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:7", + "modificationTime": "2019-12-03T11:40:45.862615Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/603_604.patch" + ], + "version": "=6.0.3" + } + ], + "proprietary": true, + "publicationTime": "2017-03-01T10:00:54Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/ljharb/qs/issues/200" + } + ], + "semver": { + "vulnerable": [ + "<6.0.4", + ">=6.1.0 <6.1.2", + ">=6.2.0 <6.2.3", + ">=6.3.0 <6.3.2" + ] + }, + "severity": "low", + "title": "Prototype Override Protection Bypass", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@6.0.4"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + } + ], + "ok": false, + "dependencyCount": 2, + "org": "another-org", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": null, + "packageManager": "npm", + "ignoreSettings": null, + "summary": "4 vulnerable dependency paths", + "remediation": { + "unresolved": [], + "upgrade": { + "node-uuid@1.4.0": { + "upgradeTo": "node-uuid@1.4.6", + "upgrades": ["node-uuid@1.4.0"], + "vulns": ["npm:node-uuid:20160328"] + }, + "qs@0.0.6": { + "upgradeTo": "qs@6.0.4", + "upgrades": ["qs@0.0.6", "qs@0.0.6", "qs@0.0.6"], + "vulns": ["npm:qs:20170213", "npm:qs:20140806", "npm:qs:20140806-1"] + } + }, + "patch": {}, + "ignore": {}, + "pin": {} + }, + "filesystemPolicy": false, + "filtered": { + "ignore": [], + "patch": [] + }, + "uniqueCount": 4, + "projectName": "shallow-goof", + "displayTargetFile": "package-lock.json" +} diff --git a/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-unresolved.json b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-unresolved.json new file mode 100644 index 00000000000..2540f1ef8ab --- /dev/null +++ b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-unresolved.json @@ -0,0 +1,470 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": ["1.4.4"], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [ + { + "comments": [], + "id": "patch:npm:node-uuid:20160328:0", + "modificationTime": "2019-12-03T11:40:45.815314Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" + ], + "version": "<=1.4.3 >=1.4.2" + } + ], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { + "vulnerable": ["<1.4.4"] + }, + "severity": "low", + "title": "Insecure Randomness", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "node-uuid@1.4.0"], + "upgradePath": [false, "node-uuid@1.4.6"], + "isUpgradable": true, + "isPatchable": false, + "name": "node-uuid", + "version": "1.4.0" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10019"], + "creationTime": "2014-08-06T06:10:22Z", + "credit": ["Dustin Shiver"], + "cvssScore": 7.5, + "description": "## Overview\n\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\n\nAffected versions of this package are vulnerable to Denial of Service (DoS).\nDuring parsing, the `qs` module may create a sparse area (an array where no elements are filled), and grow that array to the necessary size based on the indices used on it. An attacker can specify a high index value in a query string, thus making the server allocate a respectively big array. Truly large values can cause the server to run out of memory and cause it to crash - thus enabling a Denial-of-Service attack.\n\n## Remediation\n\nUpgrade `qs` to version 1.0.0 or higher.\n\n\n## Details\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.\r\n\r\nUnlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.\r\n\r\nOne popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.\r\n\r\nWhen it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.\r\n\r\nTwo common types of DoS vulnerabilities:\r\n\r\n* High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, [commons-fileupload:commons-fileupload](SNYK-JAVA-COMMONSFILEUPLOAD-30082).\r\n\r\n* Crash - An attacker sending crafted requests that could cause the system to crash. For Example, [npm `ws` package](npm:ws:20171108)\n\n## References\n\n- [GitHub Commit](https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8)\n\n- [GitHub Issue](https://github.com/visionmedia/node-querystring/issues/104)\n\n- [NVD](https://nvd.nist.gov/vuln/detail/CVE-2014-7191)\n", + "disclosureTime": "2014-08-06T06:10:22Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "id": "npm:qs:20140806", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10019"], + "CVE": ["CVE-2014-7191"], + "CWE": ["CWE-400"], + "GHSA": ["GHSA-gqgv-6jq5-jjj9"], + "NSP": [29] + }, + "language": "js", + "modificationTime": "2019-02-18T08:28:59.375824Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806:1", + "modificationTime": "2019-12-03T11:40:45.728930Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_1_snyk_npm.patch" + ], + "version": "=0.5.6" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806:0", + "modificationTime": "2019-12-03T11:40:45.741062Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_0_43a604b7847e56bba49d0ce3e222fe89569354d8_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:22Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/visionmedia/node-querystring/issues/104" + }, + { + "title": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2014-7191" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10020"], + "creationTime": "2014-08-06T06:10:23Z", + "credit": ["Tom Steele"], + "cvssScore": 6.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Denial of Service (DoS). When parsing a string representing a deeply nested object, qs will block the event loop for long periods of time. Such a delay may hold up the server's resources, keeping it from processing other requests in the meantime, thus enabling a Denial-of-Service attack.\n\n## Details\n\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.\n\nThe Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.\n\nLet’s take the following regular expression as an example:\n```js\nregex = /A(B|C+)+D/\n```\n\nThis regular expression accomplishes the following:\n- `A` The string must start with the letter 'A'\n- `(B|C+)+` The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the `+` matches one or more times). The `+` at the end of this section states that we can look for one or more matches of this section.\n- `D` Finally, we ensure this section of the string ends with a 'D'\n\nThe expression would match inputs such as `ABBD`, `ABCCCCD`, `ABCBCCCD` and `ACCCCCD`\n\nIt most cases, it doesn't take very long for a regex engine to find a match:\n\n```bash\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD\")'\n0.04s user 0.01s system 95% cpu 0.052 total\n\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX\")'\n1.79s user 0.02s system 99% cpu 1.812 total\n```\n\nThe entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.\n\nMost Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as _catastrophic backtracking_.\n\nLet's look at how our expression runs into this problem, using a shorter string: \"ACCCX\". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:\n1. CCC\n2. CC+C\n3. C+CC\n4. C+C+C.\n\nThe engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use [RegEx 101 debugger](https://regex101.com/debugger) to see the engine has to take a total of 38 steps before it can determine the string doesn't match.\n\nFrom there, the number of steps the engine must use to validate a string just continues to grow.\n\n| String | Number of C's | Number of steps |\n| -------|-------------:| -----:|\n| ACCCX | 3 | 38\n| ACCCCX | 4 | 71\n| ACCCCCX | 5 | 136\n| ACCCCCCCCCCCCCCX | 14 | 65,553\n\n\nBy the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.\n\n## Remediation\nUpgrade `qs` to version 1.0.0 or higher.\n## References\n- [Node Security Advisory](https://nodesecurity.io/advisories/28)\n", + "disclosureTime": "2014-08-06T06:10:23Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [], + "functions_new": [], + "id": "npm:qs:20140806-1", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10020"], + "CVE": ["CVE-2014-10064"], + "CWE": ["CWE-400"], + "NSP": [28] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:44.334026Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806-1:0", + "modificationTime": "2019-12-03T11:40:45.742148Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_0_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806-1:1", + "modificationTime": "2019-12-03T11:40:45.744535Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_1_snyk.patch" + ], + "version": "=0.5.6" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:23Z", + "references": [ + { + "title": "Node Security Advisory", + "url": "https://nodesecurity.io/advisories/28" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10407"], + "creationTime": "2017-02-14T11:44:54.163000Z", + "credit": ["Snyk Security Research Team"], + "cvssScore": 7.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Prototype Override Protection Bypass. By default `qs` protects against attacks that attempt to overwrite an object's existing prototype properties, such as `toString()`, `hasOwnProperty()`,etc.\r\n\r\nFrom [`qs` documentation](https://github.com/ljharb/qs):\r\n> By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use plainObjects as mentioned above, or set allowPrototypes to true which will allow user input to overwrite those properties. WARNING It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.\r\n\r\nOverwriting these properties can impact application logic, potentially allowing attackers to work around security controls, modify data, make the application unstable and more.\r\n\r\nIn versions of the package affected by this vulnerability, it is possible to circumvent this protection and overwrite prototype properties and functions by prefixing the name of the parameter with `[` or `]`. e.g. `qs.parse(\"]=toString\")` will return `{toString = true}`, as a result, calling `toString()` on the object will throw an exception.\r\n\r\n**Example:**\r\n```js\r\nqs.parse('toString=foo', { allowPrototypes: false })\r\n// {}\r\n\r\nqs.parse(\"]=toString\", { allowPrototypes: false })\r\n// {toString = true} <== prototype overwritten\r\n```\r\n\r\nFor more information, you can check out our [blog](https://snyk.io/blog/high-severity-vulnerability-qs/).\r\n\r\n## Disclosure Timeline\r\n- February 13th, 2017 - Reported the issue to package owner.\r\n- February 13th, 2017 - Issue acknowledged by package owner.\r\n- February 16th, 2017 - Partial fix released in versions `6.0.3`, `6.1.1`, `6.2.2`, `6.3.1`.\r\n- March 6th, 2017 - Final fix released in versions `6.4.0`,`6.3.2`, `6.2.3`, `6.1.2` and `6.0.4`\n## Remediation\nUpgrade `qs` to version 6.0.4, 6.1.2, 6.2.3, 6.3.2 or higher.\n## References\n- [GitHub Commit](https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d)\n- [GitHub Issue](https://github.com/ljharb/qs/issues/200)\n", + "disclosureTime": "2017-02-13T00:00:00Z", + "exploit": "Not Defined", + "fixedIn": ["6.0.4", "6.1.2", "6.2.3", "6.3.2"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "id": "npm:qs:20170213", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10407"], + "CVE": ["CVE-2017-1000048"], + "CWE": ["CWE-20"] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:53.880024Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20170213:0", + "modificationTime": "2019-12-03T11:40:45.855245Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/630_632.patch" + ], + "version": "=6.3.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:1", + "modificationTime": "2019-12-03T11:40:45.856271Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/631_632.patch" + ], + "version": "=6.3.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:2", + "modificationTime": "2019-12-03T11:40:45.857318Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/621_623.patch" + ], + "version": "=6.2.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:3", + "modificationTime": "2019-12-03T11:40:45.858334Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/622_623.patch" + ], + "version": "=6.2.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:4", + "modificationTime": "2019-12-03T11:40:45.859411Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/610_612.patch" + ], + "version": "=6.1.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:5", + "modificationTime": "2019-12-03T11:40:45.860523Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/611_612.patch" + ], + "version": "=6.1.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:6", + "modificationTime": "2019-12-03T11:40:45.861504Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/602_604.patch" + ], + "version": "=6.0.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:7", + "modificationTime": "2019-12-03T11:40:45.862615Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/603_604.patch" + ], + "version": "=6.0.3" + } + ], + "proprietary": true, + "publicationTime": "2017-03-01T10:00:54Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/ljharb/qs/issues/200" + } + ], + "semver": { + "vulnerable": [ + "<6.0.4", + ">=6.1.0 <6.1.2", + ">=6.2.0 <6.2.3", + ">=6.3.0 <6.3.2" + ] + }, + "severity": "low", + "title": "Prototype Override Protection Bypass", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@6.0.4"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + } + ], + "ok": false, + "dependencyCount": 2, + "org": "another-org", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": null, + "packageManager": "npm", + "ignoreSettings": null, + "summary": "4 vulnerable dependency paths", + "remediation": { + "unresolved": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": [], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { "vulnerable": ["*"] }, + "severity": "low", + "originalSeverity": "medium", + "title": "Malicious Package", + "isPinnable": false, + "from": ["no-fix-app@1.0.0", "cxct@0.0.1-security"], + "upgradePath": [], + "isUpgradable": false, + "isPatchable": false, + "name": "cxct", + "version": "0.0.1-security" + } + ], + "upgrade": {}, + "patch": {}, + "ignore": {}, + "pin": {} + }, + "filesystemPolicy": false, + "filtered": { + "ignore": [], + "patch": [] + }, + "uniqueCount": 4, + "projectName": "shallow-goof", + "displayTargetFile": "package-lock.json" +} diff --git a/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-upgrade.json b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-upgrade.json new file mode 100644 index 00000000000..1b7389fac92 --- /dev/null +++ b/test/acceptance/fixtures/npm-package-with-severity-override/test-graph-result-upgrade.json @@ -0,0 +1,430 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": ["1.4.4"], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [ + { + "comments": [], + "id": "patch:npm:node-uuid:20160328:0", + "modificationTime": "2019-12-03T11:40:45.815314Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" + ], + "version": "<=1.4.3 >=1.4.2" + } + ], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { + "vulnerable": ["<1.4.4"] + }, + "severity": "low", + "title": "Insecure Randomness", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "node-uuid@1.4.0"], + "upgradePath": [false, "node-uuid@1.4.6"], + "isUpgradable": true, + "isPatchable": false, + "name": "node-uuid", + "version": "1.4.0" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10019"], + "creationTime": "2014-08-06T06:10:22Z", + "credit": ["Dustin Shiver"], + "cvssScore": 7.5, + "description": "## Overview\n\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\n\nAffected versions of this package are vulnerable to Denial of Service (DoS).\nDuring parsing, the `qs` module may create a sparse area (an array where no elements are filled), and grow that array to the necessary size based on the indices used on it. An attacker can specify a high index value in a query string, thus making the server allocate a respectively big array. Truly large values can cause the server to run out of memory and cause it to crash - thus enabling a Denial-of-Service attack.\n\n## Remediation\n\nUpgrade `qs` to version 1.0.0 or higher.\n\n\n## Details\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.\r\n\r\nUnlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.\r\n\r\nOne popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.\r\n\r\nWhen it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.\r\n\r\nTwo common types of DoS vulnerabilities:\r\n\r\n* High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, [commons-fileupload:commons-fileupload](SNYK-JAVA-COMMONSFILEUPLOAD-30082).\r\n\r\n* Crash - An attacker sending crafted requests that could cause the system to crash. For Example, [npm `ws` package](npm:ws:20171108)\n\n## References\n\n- [GitHub Commit](https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8)\n\n- [GitHub Issue](https://github.com/visionmedia/node-querystring/issues/104)\n\n- [NVD](https://nvd.nist.gov/vuln/detail/CVE-2014-7191)\n", + "disclosureTime": "2014-08-06T06:10:22Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "index.js", + "functionName": "compact" + }, + "version": ["<1.0.0"] + } + ], + "id": "npm:qs:20140806", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10019"], + "CVE": ["CVE-2014-7191"], + "CWE": ["CWE-400"], + "GHSA": ["GHSA-gqgv-6jq5-jjj9"], + "NSP": [29] + }, + "language": "js", + "modificationTime": "2019-02-18T08:28:59.375824Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806:1", + "modificationTime": "2019-12-03T11:40:45.728930Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_1_snyk_npm.patch" + ], + "version": "=0.5.6" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806:0", + "modificationTime": "2019-12-03T11:40:45.741062Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806/qs_20140806_0_0_43a604b7847e56bba49d0ce3e222fe89569354d8_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:22Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/tj/node-querystring/pull/114/commits/43a604b7847e56bba49d0ce3e222fe89569354d8" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/visionmedia/node-querystring/issues/104" + }, + { + "title": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2014-7191" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10020"], + "creationTime": "2014-08-06T06:10:23Z", + "credit": ["Tom Steele"], + "cvssScore": 6.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Denial of Service (DoS). When parsing a string representing a deeply nested object, qs will block the event loop for long periods of time. Such a delay may hold up the server's resources, keeping it from processing other requests in the meantime, thus enabling a Denial-of-Service attack.\n\n## Details\n\nDenial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.\n\nThe Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.\n\nLet’s take the following regular expression as an example:\n```js\nregex = /A(B|C+)+D/\n```\n\nThis regular expression accomplishes the following:\n- `A` The string must start with the letter 'A'\n- `(B|C+)+` The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the `+` matches one or more times). The `+` at the end of this section states that we can look for one or more matches of this section.\n- `D` Finally, we ensure this section of the string ends with a 'D'\n\nThe expression would match inputs such as `ABBD`, `ABCCCCD`, `ABCBCCCD` and `ACCCCCD`\n\nIt most cases, it doesn't take very long for a regex engine to find a match:\n\n```bash\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD\")'\n0.04s user 0.01s system 95% cpu 0.052 total\n\n$ time node -e '/A(B|C+)+D/.test(\"ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX\")'\n1.79s user 0.02s system 99% cpu 1.812 total\n```\n\nThe entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.\n\nMost Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as _catastrophic backtracking_.\n\nLet's look at how our expression runs into this problem, using a shorter string: \"ACCCX\". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:\n1. CCC\n2. CC+C\n3. C+CC\n4. C+C+C.\n\nThe engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use [RegEx 101 debugger](https://regex101.com/debugger) to see the engine has to take a total of 38 steps before it can determine the string doesn't match.\n\nFrom there, the number of steps the engine must use to validate a string just continues to grow.\n\n| String | Number of C's | Number of steps |\n| -------|-------------:| -----:|\n| ACCCX | 3 | 38\n| ACCCCX | 4 | 71\n| ACCCCCX | 5 | 136\n| ACCCCCCCCCCCCCCX | 14 | 65,553\n\n\nBy the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.\n\n## Remediation\nUpgrade `qs` to version 1.0.0 or higher.\n## References\n- [Node Security Advisory](https://nodesecurity.io/advisories/28)\n", + "disclosureTime": "2014-08-06T06:10:23Z", + "exploit": "Not Defined", + "fixedIn": ["1.0.0"], + "functions": [], + "functions_new": [], + "id": "npm:qs:20140806-1", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10020"], + "CVE": ["CVE-2014-10064"], + "CWE": ["CWE-400"], + "NSP": [28] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:44.334026Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20140806-1:0", + "modificationTime": "2019-12-03T11:40:45.742148Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_0_snyk.patch" + ], + "version": "<1.0.0 >=0.6.5" + }, + { + "comments": [], + "id": "patch:npm:qs:20140806-1:1", + "modificationTime": "2019-12-03T11:40:45.744535Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20140806-1/qs_20140806-1_0_1_snyk.patch" + ], + "version": "=0.5.6" + } + ], + "proprietary": false, + "publicationTime": "2014-08-06T06:10:23Z", + "references": [ + { + "title": "Node Security Advisory", + "url": "https://nodesecurity.io/advisories/28" + } + ], + "semver": { + "vulnerable": ["<1.0.0"] + }, + "severity": "low", + "title": "Denial of Service (DoS)", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@1.0.0"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + }, + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "alternativeIds": ["SNYK-JS-QS-10407"], + "creationTime": "2017-02-14T11:44:54.163000Z", + "credit": ["Snyk Security Research Team"], + "cvssScore": 7.5, + "description": "## Overview\n[qs](https://www.npmjs.com/package/qs) is a querystring parser that supports nesting and arrays, with a depth limit.\n\nAffected versions of this package are vulnerable to Prototype Override Protection Bypass. By default `qs` protects against attacks that attempt to overwrite an object's existing prototype properties, such as `toString()`, `hasOwnProperty()`,etc.\r\n\r\nFrom [`qs` documentation](https://github.com/ljharb/qs):\r\n> By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use plainObjects as mentioned above, or set allowPrototypes to true which will allow user input to overwrite those properties. WARNING It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.\r\n\r\nOverwriting these properties can impact application logic, potentially allowing attackers to work around security controls, modify data, make the application unstable and more.\r\n\r\nIn versions of the package affected by this vulnerability, it is possible to circumvent this protection and overwrite prototype properties and functions by prefixing the name of the parameter with `[` or `]`. e.g. `qs.parse(\"]=toString\")` will return `{toString = true}`, as a result, calling `toString()` on the object will throw an exception.\r\n\r\n**Example:**\r\n```js\r\nqs.parse('toString=foo', { allowPrototypes: false })\r\n// {}\r\n\r\nqs.parse(\"]=toString\", { allowPrototypes: false })\r\n// {toString = true} <== prototype overwritten\r\n```\r\n\r\nFor more information, you can check out our [blog](https://snyk.io/blog/high-severity-vulnerability-qs/).\r\n\r\n## Disclosure Timeline\r\n- February 13th, 2017 - Reported the issue to package owner.\r\n- February 13th, 2017 - Issue acknowledged by package owner.\r\n- February 16th, 2017 - Partial fix released in versions `6.0.3`, `6.1.1`, `6.2.2`, `6.3.1`.\r\n- March 6th, 2017 - Final fix released in versions `6.4.0`,`6.3.2`, `6.2.3`, `6.1.2` and `6.0.4`\n## Remediation\nUpgrade `qs` to version 6.0.4, 6.1.2, 6.2.3, 6.3.2 or higher.\n## References\n- [GitHub Commit](https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d)\n- [GitHub Issue](https://github.com/ljharb/qs/issues/200)\n", + "disclosureTime": "2017-02-13T00:00:00Z", + "exploit": "Not Defined", + "fixedIn": ["6.0.4", "6.1.2", "6.2.3", "6.3.2"], + "functions": [ + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "className": null, + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "functions_new": [ + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "internals.parseObject" + }, + "version": ["<6.0.4"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObject" + }, + "version": [">=6.2.0 <6.2.3", "6.3.0"] + }, + { + "functionId": { + "filePath": "lib/parse.js", + "functionName": "parseObjectRecursive" + }, + "version": [">=6.3.1 <6.3.2"] + } + ], + "id": "npm:qs:20170213", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-QS-10407"], + "CVE": ["CVE-2017-1000048"], + "CWE": ["CWE-20"] + }, + "language": "js", + "modificationTime": "2020-06-12T14:36:53.880024Z", + "moduleName": "qs", + "packageManager": "npm", + "packageName": "qs", + "patches": [ + { + "comments": [], + "id": "patch:npm:qs:20170213:0", + "modificationTime": "2019-12-03T11:40:45.855245Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/630_632.patch" + ], + "version": "=6.3.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:1", + "modificationTime": "2019-12-03T11:40:45.856271Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/631_632.patch" + ], + "version": "=6.3.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:2", + "modificationTime": "2019-12-03T11:40:45.857318Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/621_623.patch" + ], + "version": "=6.2.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:3", + "modificationTime": "2019-12-03T11:40:45.858334Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/622_623.patch" + ], + "version": "=6.2.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:4", + "modificationTime": "2019-12-03T11:40:45.859411Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/610_612.patch" + ], + "version": "=6.1.0" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:5", + "modificationTime": "2019-12-03T11:40:45.860523Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/611_612.patch" + ], + "version": "=6.1.1" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:6", + "modificationTime": "2019-12-03T11:40:45.861504Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/602_604.patch" + ], + "version": "=6.0.2" + }, + { + "comments": [], + "id": "patch:npm:qs:20170213:7", + "modificationTime": "2019-12-03T11:40:45.862615Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/qs/20170213/603_604.patch" + ], + "version": "=6.0.3" + } + ], + "proprietary": true, + "publicationTime": "2017-03-01T10:00:54Z", + "references": [ + { + "title": "GitHub Commit", + "url": "https://github.com/ljharb/qs/commit/beade029171b8cef9cee0d03ebe577e2dd84976d" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/ljharb/qs/issues/200" + } + ], + "semver": { + "vulnerable": [ + "<6.0.4", + ">=6.1.0 <6.1.2", + ">=6.2.0 <6.2.3", + ">=6.3.0 <6.3.2" + ] + }, + "severity": "low", + "title": "Prototype Override Protection Bypass", + "originalSeverity": "high", + "from": ["shallow-goof@0.0.1", "qs@0.0.6"], + "upgradePath": [false, "qs@6.0.4"], + "isUpgradable": true, + "isPatchable": false, + "name": "qs", + "version": "0.0.6" + } + ], + "ok": false, + "dependencyCount": 2, + "org": "another-org", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": null, + "packageManager": "npm", + "ignoreSettings": null, + "summary": "4 vulnerable dependency paths", + "remediation": { + "unresolved": [], + "upgrade": { + "node-uuid@1.4.0": { + "upgradeTo": "node-uuid@1.4.6", + "upgrades": ["node-uuid@1.4.0"], + "vulns": ["npm:node-uuid:20160328"] + }, + "qs@0.0.6": { + "upgradeTo": "qs@6.0.4", + "upgrades": ["qs@0.0.6", "qs@0.0.6", "qs@0.0.6"], + "vulns": ["npm:qs:20170213", "npm:qs:20140806", "npm:qs:20140806-1"] + } + }, + "patch": {}, + "ignore": {}, + "pin": {} + }, + "filesystemPolicy": false, + "filtered": { + "ignore": [], + "patch": [] + }, + "uniqueCount": 4, + "projectName": "shallow-goof", + "displayTargetFile": "package-lock.json" +} diff --git a/test/fixtures/original-severity-vulns.json b/test/fixtures/original-severity-vulns.json new file mode 100644 index 00000000000..2e1e8e6dd0a --- /dev/null +++ b/test/fixtures/original-severity-vulns.json @@ -0,0 +1,92 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "alternativeIds": ["SNYK-JS-NODEUUID-10089"], + "creationTime": "2016-03-28T22:00:02.566000Z", + "credit": ["Fedot Praslov"], + "cvssScore": 4.2, + "description": "## Overview\r\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\r\n\r\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\r\n\r\n## Remediation\r\nUpgrade `node-uuid` to version 1.4.4 or greater.\r\n\r\n## References\r\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\r\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)", + "disclosureTime": "2016-03-28T21:29:30Z", + "exploit": "Not Defined", + "fixedIn": ["1.4.4"], + "functions": [], + "functions_new": [], + "id": "npm:node-uuid:20160328", + "identifiers": { + "ALTERNATIVE": ["SNYK-JS-NODEUUID-10089"], + "CVE": ["CVE-2015-8851"], + "CWE": ["CWE-330"], + "GHSA": ["GHSA-265q-28rp-chq5"], + "NSP": [93] + }, + "language": "js", + "modificationTime": "2019-12-02T14:38:43.034395Z", + "moduleName": "node-uuid", + "packageManager": "npm", + "packageName": "node-uuid", + "patches": [ + { + "comments": [], + "id": "patch:npm:node-uuid:20160328:0", + "modificationTime": "2019-12-03T11:40:45.815314Z", + "urls": [ + "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" + ], + "version": "<=1.4.3 >=1.4.2" + } + ], + "proprietary": false, + "publicationTime": "2016-03-28T22:00:02Z", + "references": [ + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/108" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/broofa/node-uuid/issues/122" + } + ], + "semver": { "vulnerable": ["<1.4.4"] }, + "severity": "low", + "title": "Insecure Randomness", + "originalSeverity": "medium", + "from": ["shallow-goof@0.0.1", "node-uuid@1.4.0"], + "upgradePath": [false, "node-uuid@1.4.6"], + "isUpgradable": true, + "isPatchable": false, + "name": "node-uuid", + "version": "1.4.0", + "parentDepType": "prod" + } + ], + "ok": false, + "dependencyCount": 1, + "org": "another-org", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": null, + "packageManager": "npm", + "projectId": "79b0b833-25d7-4f11-bc58-dbfc55a4e5c7", + "ignoreSettings": null, + "summary": "1 vulnerable dependency paths", + "remediation": { + "unresolved": [], + "upgrade": { + "node-uuid@1.4.0": { + "upgradeTo": "node-uuid@1.4.6", + "upgrades": ["node-uuid@1.4.0"], + "vulns": ["npm:node-uuid:20160328"] + } + }, + "patch": {}, + "ignore": {}, + "pin": {} + }, + "filesystemPolicy": true, + "filtered": { "ignore": [], "patch": [] }, + "uniqueCount": 4, + "projectName": "shallow-goof", + "displayTargetFile": "package.json" +} diff --git a/test/prompts-show-original-severity.test.ts b/test/prompts-show-original-severity.test.ts new file mode 100644 index 00000000000..66451122d63 --- /dev/null +++ b/test/prompts-show-original-severity.test.ts @@ -0,0 +1,64 @@ +import * as fs from 'fs'; +import { test } from 'tap'; +import * as path from 'path'; +import { getPrompts } from '../src/cli/commands/protect/prompts'; + +test('wizard prompts should show original severity', async (t) => { + const id = 'npm:node-uuid:20160328'; + const vulnsJson = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, './fixtures/original-severity-vulns.json'), + 'utf-8', + ), + ); + + const { vulnerabilities, policy } = vulnsJson; + + try { + const allPrompts = getPrompts(vulnerabilities, policy); + + const prompt = allPrompts + .filter((p) => { + return p.name.indexOf(id) === 0; + }) + .shift(); + + t.match( + prompt?.message, + 'Low (originally Medium) severity vuln found in node-uuid@1.4.0, introduced via node-uuid@1.4.0', + ); + } catch (e) { + t.threw(e); + } +}); + +test('wizard prompts should not show original severity if its the same', async (t) => { + const id = 'npm:node-uuid:20160328'; + const vulnsJson = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, './fixtures/original-severity-vulns.json'), + 'utf-8', + ), + ); + + const { vulnerabilities, policy } = vulnsJson; + + vulnerabilities[0].originalSeverity = 'low'; + + try { + const allPrompts = getPrompts(vulnerabilities, policy); + + const prompt = allPrompts + .filter((p) => { + return p.name.indexOf(id) === 0; + }) + .shift(); + + t.match( + prompt?.message, + 'Low severity vuln found in node-uuid@1.4.0, introduced via node-uuid@1.4.0', + ); + } catch (e) { + t.threw(e); + } +});