diff --git a/node/lib/retire.js b/node/lib/retire.js index 851dd975..b25ed259 100644 --- a/node/lib/retire.js +++ b/node/lib/retire.js @@ -103,6 +103,9 @@ function check(results, repo) { if (isDefined(vulns[i].atOrAbove) && !isAtOrAbove(result.version, vulns[i].atOrAbove)) { continue; } + if (isDefined(vulns[i].excludes) && vulns[i].excludes.indexOf(result.version) !== -1) { + continue; + } var vulnerability = { info: vulns[i].info, below: vulns[i].below, atOrAbove: vulns[i].atOrAbove }; if (vulns[i].severity) { vulnerability.severity = vulns[i].severity; diff --git a/node/spec/tests/versions.spec.ts b/node/spec/tests/versions.spec.ts index 7bb79b78..e550e092 100644 --- a/node/spec/tests/versions.spec.ts +++ b/node/spec/tests/versions.spec.ts @@ -67,4 +67,16 @@ describe('versions', function () { assert.isNotVulnerable(result); done(); }); + it('should_not_be_vulnerable_when_version_in_excludes_list', function (done) { + repo.jquery.vulnerabilities = [{ atOrAbove: '1.0.0', below: '3.0.0', excludes: ['1.12.4-aem'] }]; + const result = retire.scanUri('https://ajax.googleapis.com/ajax/libs/jquery/1.12.4-aem/jquery.min.js', repo); + assert.isNotVulnerable(result); + done(); + }); + it('should_be_vulnerable_when_similar_version_not_in_excludes_list', function (done) { + repo.jquery.vulnerabilities = [{ atOrAbove: '1.0.0', below: '3.0.0', excludes: ['1.12.4-aem'] }]; + const result = retire.scanUri('https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js', repo); + assert.isVulnerable(result); + done(); + }); }); diff --git a/node/src/repo.ts b/node/src/repo.ts index 9306dd60..8bfafb23 100644 --- a/node/src/repo.ts +++ b/node/src/repo.ts @@ -21,6 +21,7 @@ export function validateRepository( .object({ below: versionValidator, atOrAbove: versionValidator.optional(), + excludes: z.array(versionValidator).optional(), severity: z.enum(keys), cwe: z.array(z.string().regex(/^CWE-[0-9]+$/)).min(1), identifiers: z diff --git a/node/src/types.ts b/node/src/types.ts index 52c9081b..3e9fe69b 100644 --- a/node/src/types.ts +++ b/node/src/types.ts @@ -23,6 +23,7 @@ export type Repository = Record< export type Vulnerability = { below: string; atOrAbove?: string; + excludes?: string[]; severity: SeverityLevel; cwe: string[]; identifiers: { diff --git a/repository/convertFormat.js b/repository/convertFormat.js index 63db0047..443e63a2 100644 --- a/repository/convertFormat.js +++ b/repository/convertFormat.js @@ -28,12 +28,16 @@ function convertToOldFormat( const { ranges, summary, identifiers, info, ...rest } = v; ranges.forEach((r) => { - vulns.push({ + const vuln = { ...r, ...rest, identifiers: { summary, ...identifiers }, info, - }); + }; + if (r.excludes) { + vuln.excludes = r.excludes; + } + vulns.push(vuln); }); }); vulns.sort((a, b) => { diff --git a/repository/jsrepository-master.json b/repository/jsrepository-master.json index 0febf9ca..342f17a5 100644 --- a/repository/jsrepository-master.json +++ b/repository/jsrepository-master.json @@ -98,7 +98,8 @@ }, { "atOrAbove": "1.12.3", - "below": "3.0.0-beta1" + "below": "3.0.0-beta1", + "excludes": ["1.12.4-aem"] } ], "summary": "3rd party CORS request may execute", @@ -138,7 +139,8 @@ "ranges": [ { "atOrAbove": "1.1.4", - "below": "3.4.0" + "below": "3.4.0", + "excludes": ["1.12.4-aem"] } ], "summary": "jQuery before 3.4.0, as used in Drupal, Backdrop CMS, and other products, mishandles jQuery.extend(true, {}, ...) because of Object.prototype pollution", @@ -159,7 +161,8 @@ "ranges": [ { "atOrAbove": "1.2.0", - "below": "3.5.0" + "below": "3.5.0", + "excludes": ["1.12.4-aem"] } ], "summary": "Regex in its jQuery.htmlPrefilter sometimes may introduce XSS", @@ -176,7 +179,8 @@ "ranges": [ { "atOrAbove": "1.0.3", - "below": "3.5.0" + "below": "3.5.0", + "excludes": ["1.12.4-aem"] } ], "summary": "passing HTML containing