From a9ef562effed8b3e434356b6abe364ef9b4d67a7 Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Mon, 13 Feb 2023 19:00:36 +0100 Subject: [PATCH] feat(vulnerabilities): add additional severity indicators and improve layout (#20363) Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com> --- .../process/vulnerabilities.spec.ts | 174 ++++++++++++++++-- .../repository/process/vulnerabilities.ts | 40 +++- 2 files changed, 191 insertions(+), 23 deletions(-) diff --git a/lib/workers/repository/process/vulnerabilities.spec.ts b/lib/workers/repository/process/vulnerabilities.spec.ts index 8a03529383..dc3146ad5c 100644 --- a/lib/workers/repository/process/vulnerabilities.spec.ts +++ b/lib/workers/repository/process/vulnerabilities.spec.ts @@ -492,18 +492,18 @@ describe('workers/repository/process/vulnerabilities', () => { <details> <summary>More information</summary> - ### Details + #### Details HTTP pipelining issues and request smuggling attacks are possible due to incorrect Transfer encoding header parsing. It is possible conduct HTTP request smuggling attacks (CL:TE/TE:TE) by sending invalid Transfer Encoding headers. By manipulating the HTTP response the attacker could poison a web-cache, perform an XSS attack, or obtain sensitive information from requests other than their own. - ### Severity - - Score: 6.5 / 10 (Medium) - - Vector: \`CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N\` + #### Severity + - CVSS Score: 6.5 / 10 (Medium) + - Vector String: \`CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N\` - ### References + #### References No references. This data is provided by [OSV](https://osv.dev/vulnerability/RUSTSEC-2020-0031) and the [Rust Advisory Database](https://github.com/RustSec/advisory-db) ([CC0 1.0](https://github.com/rustsec/advisory-db/blob/main/LICENSE.txt)). @@ -664,13 +664,13 @@ describe('workers/repository/process/vulnerabilities', () => { <details> <summary>More information</summary> - ### Details + #### Details No details. - ### Severity + #### Severity Unknown severity. - ### References + #### References No references. This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-xxxx-yyyy-zzzz) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). @@ -742,14 +742,14 @@ describe('workers/repository/process/vulnerabilities', () => { <details> <summary>More information</summary> - ### Details + #### Details No details. - ### Severity - - Score: Unknown - - Vector: \`some-invalid-score\` + #### Severity + - CVSS Score: Unknown + - Vector String: \`some-invalid-score\` - ### References + #### References No references. This data is provided by [OSV](https://osv.dev/vulnerability/PYSEC-2022-303) and the [PyPI Advisory Database](https://github.com/pypa/advisory-database) ([CC-BY 4.0](https://github.com/pypa/advisory-database/blob/main/LICENSE)). @@ -759,5 +759,153 @@ describe('workers/repository/process/vulnerabilities', () => { }, ]); }); + + it('show severity text in GHSA advisories without CVSS score', async () => { + const packageFiles: Record<string, PackageFile[]> = { + npm: [ + { + deps: [ + { depName: 'lodash', currentValue: '4.17.10', datasource: 'npm' }, + ], + }, + ], + }; + + getVulnerabilitiesMock.mockResolvedValueOnce([ + { + ...lodashVulnerability, + database_specific: { + severity: 'MODERATE', + }, + }, + ]); + + await vulnerabilities.fetchVulnerabilities(config, packageFiles); + + expect(config.packageRules).toHaveLength(1); + expect(config.packageRules).toMatchObject([ + { + matchDatasources: ['npm'], + matchPackageNames: ['lodash'], + matchCurrentVersion: '4.17.10', + allowedVersions: '4.17.11', + isVulnerabilityAlert: true, + prBodyNotes: [ + '\n\n' + + codeBlock` + --- + + ### [GHSA-x5rq-j2xg-h7qm](https://github.com/advisories/GHSA-x5rq-j2xg-h7qm) + + <details> + <summary>More information</summary> + + #### Details + No details. + + #### Severity + Moderate + + #### References + - [https://nvd.nist.gov/vuln/detail/CVE-2019-1010266](https://nvd.nist.gov/vuln/detail/CVE-2019-1010266) + + This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-x5rq-j2xg-h7qm) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). + </details> + `, + ], + }, + ]); + }); + + it('formats headings of vulnerability details', async () => { + const packageFiles: Record<string, PackageFile[]> = { + regex: [ + { + deps: [ + { + depName: 'sys-info', + currentValue: '0.6.0', + datasource: 'crate', + }, + ], + }, + ], + }; + getVulnerabilitiesMock.mockResolvedValueOnce([ + { + id: 'RUSTSEC-2020-0100', + summary: + 'Double free when calling `sys_info::disk_info` from multiple threads', + details: + 'Affected versions of `sys-info` use a static, global, list to store temporary disk information while running. The function that cleans up this list,\n`DFCleanup`, assumes a single threaded environment and will try to free the same memory twice in a multithreaded environment.\n\nThis results in consistent double-frees and segfaults when calling `sys_info::disk_info` from multiple threads at once.\n\nThe issue was fixed by moving the global variable into a local scope.\n\n## Safer Alternatives:\n - [`sysinfo`](https://crates.io/crates/sysinfo)', + aliases: ['CVE-2020-36434'], + modified: '', + affected: [ + { + package: { + name: 'sys-info', + ecosystem: 'crates.io', + purl: 'pkg:cargo/sys-info', + }, + ranges: [ + { + type: 'SEMVER', + events: [{ introduced: '0.0.0-0' }, { fixed: '0.8.0' }], + }, + ], + database_specific: { + cvss: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H', + }, + }, + ], + }, + ]); + + await vulnerabilities.fetchVulnerabilities(config, packageFiles); + + expect(config.packageRules).toHaveLength(1); + expect(config.packageRules).toMatchObject([ + { + matchDatasources: ['crate'], + matchPackageNames: ['sys-info'], + matchCurrentVersion: '0.6.0', + allowedVersions: '0.8.0', + isVulnerabilityAlert: true, + prBodyNotes: [ + '\n\n' + + codeBlock` + --- + + ### Double free when calling \`sys_info::disk_info\` from multiple threads + [CVE-2020-36434](https://nvd.nist.gov/vuln/detail/CVE-2020-36434) / [RUSTSEC-2020-0100](https://rustsec.org/advisories/RUSTSEC-2020-0100.html) + + <details> + <summary>More information</summary> + + #### Details + Affected versions of \`sys-info\` use a static, global, list to store temporary disk information while running. The function that cleans up this list, + \`DFCleanup\`, assumes a single threaded environment and will try to free the same memory twice in a multithreaded environment. + + This results in consistent double-frees and segfaults when calling \`sys_info::disk_info\` from multiple threads at once. + + The issue was fixed by moving the global variable into a local scope. + + ##### Safer Alternatives: + - [\`sysinfo\`](https://crates.io/crates/sysinfo) + + #### Severity + - CVSS Score: 9.8 / 10 (Critical) + - Vector String: \`CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\` + + #### References + No references. + + This data is provided by [OSV](https://osv.dev/vulnerability/RUSTSEC-2020-0100) and the [Rust Advisory Database](https://github.com/RustSec/advisory-db) ([CC0 1.0](https://github.com/rustsec/advisory-db/blob/main/LICENSE.txt)). + </details> + `, + ], + }, + ]); + }); }); }); diff --git a/lib/workers/repository/process/vulnerabilities.ts b/lib/workers/repository/process/vulnerabilities.ts index 3ab53afe7a..1b51870cdb 100644 --- a/lib/workers/repository/process/vulnerabilities.ts +++ b/lib/workers/repository/process/vulnerabilities.ts @@ -190,7 +190,8 @@ export class Vulnerabilities { packageName, depVersion, fixedVersion, - vulnerability + vulnerability, + affected ); packageRules.push(rule); } @@ -398,7 +399,8 @@ export class Vulnerabilities { packageName: string, depVersion: string, fixedVersion: string, - vulnerability: Osv.Vulnerability + vulnerability: Osv.Vulnerability, + affected: Osv.Affected ): PackageRule { return { matchDatasources: [dep.datasource!], @@ -406,7 +408,7 @@ export class Vulnerabilities { matchCurrentVersion: depVersion, allowedVersions: fixedVersion, isVulnerabilityAlert: true, - prBodyNotes: this.generatePrBodyNotes(vulnerability), + prBodyNotes: this.generatePrBodyNotes(vulnerability, affected), force: { ...packageFileConfig.vulnerabilityAlerts, }, @@ -428,7 +430,10 @@ export class Vulnerabilities { return ['', '']; } - private generatePrBodyNotes(vulnerability: Osv.Vulnerability): string[] { + private generatePrBodyNotes( + vulnerability: Osv.Vulnerability, + affected: Osv.Affected + ): string[] { let aliases = [vulnerability.id].concat(vulnerability.aliases ?? []).sort(); aliases = aliases.map((id) => { if (id.startsWith('CVE-')) { @@ -448,22 +453,37 @@ export class Vulnerabilities { content += vulnerability.summary ? `${vulnerability.summary}\n` : ''; content += `${aliases.join(' / ')}\n`; content += `\n<details>\n<summary>More information</summary>\n`; - content += `### Details\n${vulnerability.details ?? 'No details.'}\n`; - content += '### Severity\n'; + const details = vulnerability.details?.replace( + regEx(/^#{1,4} /gm), + '##### ' + ); + content += `#### Details\n${details ?? 'No details.'}\n`; + + content += '#### Severity\n'; const cvssVector = vulnerability.severity?.find((e) => e.type === 'CVSS_V3')?.score ?? - vulnerability.severity?.[0]?.score; + vulnerability.severity?.[0]?.score ?? + (affected.database_specific?.cvss as string); // RUSTSEC if (cvssVector) { const [baseScore, severity] = this.evaluateCvssVector(cvssVector); const score = baseScore ? `${baseScore} / 10 (${severity})` : 'Unknown'; - content += `- Score: ${score}\n`; - content += `- Vector: \`${cvssVector}\`\n`; + content += `- CVSS Score: ${score}\n`; + content += `- Vector String: \`${cvssVector}\`\n`; + } else if ( + vulnerability.id.startsWith('GHSA-') && + vulnerability.database_specific?.severity + ) { + const severity = vulnerability.database_specific.severity as string; + content += + severity.charAt(0).toUpperCase() + + severity.slice(1).toLowerCase() + + '\n'; } else { content += 'Unknown severity.\n'; } - content += `\n### References\n${ + content += `\n#### References\n${ vulnerability.references ?.map((ref) => { return `- [${ref.url}](${ref.url})`; -- GitLab