mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-21 23:00:42 -08:00
refactor(cyclonedx): add intermediate representation (#4490)
This commit is contained in:
@@ -12,9 +12,6 @@ trivy sbom [flags] SBOM_PATH
|
||||
# Scan CycloneDX and show the result in tables
|
||||
$ trivy sbom /path/to/report.cdx
|
||||
|
||||
# Scan CycloneDX and generate a CycloneDX report
|
||||
$ trivy sbom --format cyclonedx /path/to/report.cdx
|
||||
|
||||
# Scan CycloneDX-type attestation and show the result in tables
|
||||
$ trivy sbom /path/to/report.cdx.intoto.jsonl
|
||||
|
||||
|
||||
@@ -28,10 +28,6 @@ Trivy supports CycloneDX as an input.
|
||||
$ trivy sbom /path/to/cyclonedx.json
|
||||
```
|
||||
|
||||
!!! note
|
||||
If you want to generate a CycloneDX report from a CycloneDX input, please be aware that the output stores references to your original CycloneDX report and contains only detected vulnerabilities, not components.
|
||||
The report is called [BOV](https://cyclonedx.org/capabilities/sbom/).
|
||||
|
||||
## SPDX
|
||||
Trivy supports the SPDX SBOM as an input.
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ func TestClientServerWithCycloneDX(t *testing.T) {
|
||||
Input: "testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz",
|
||||
},
|
||||
wantComponentsCount: 161,
|
||||
wantDependenciesCount: 80,
|
||||
wantDependenciesCount: 162,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -30,16 +30,30 @@ func TestSBOM(t *testing.T) {
|
||||
name: "centos7 cyclonedx",
|
||||
args: args{
|
||||
input: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
|
||||
format: "cyclonedx",
|
||||
format: "json",
|
||||
artifactType: "cyclonedx",
|
||||
},
|
||||
golden: "testdata/centos-7-cyclonedx.json.golden",
|
||||
golden: "testdata/centos-7.json.golden",
|
||||
override: types.Report{
|
||||
ArtifactName: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
|
||||
ArtifactType: ftypes.ArtifactType("cyclonedx"),
|
||||
Results: types.Results{
|
||||
{
|
||||
Target: "testdata/fixtures/sbom/centos-7-cyclonedx.json (centos 7.6.1810)",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"},
|
||||
{PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"},
|
||||
{PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fluentd-multiple-lockfiles cyclonedx",
|
||||
args: args{
|
||||
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
|
||||
format: "cyclonedx",
|
||||
format: "json",
|
||||
artifactType: "cyclonedx",
|
||||
},
|
||||
golden: "testdata/fluentd-multiple-lockfiles-cyclonedx.json.golden",
|
||||
@@ -48,10 +62,24 @@ func TestSBOM(t *testing.T) {
|
||||
name: "centos7 in in-toto attestation",
|
||||
args: args{
|
||||
input: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
|
||||
format: "cyclonedx",
|
||||
format: "json",
|
||||
artifactType: "cyclonedx",
|
||||
},
|
||||
golden: "testdata/centos-7-cyclonedx.json.golden",
|
||||
golden: "testdata/centos-7.json.golden",
|
||||
override: types.Report{
|
||||
ArtifactName: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
|
||||
ArtifactType: ftypes.ArtifactType("cyclonedx"),
|
||||
Results: types.Results{
|
||||
{
|
||||
Target: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl (centos 7.6.1810)",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"},
|
||||
{PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"},
|
||||
{PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "centos7 spdx tag-value",
|
||||
@@ -131,8 +159,6 @@ func TestSBOM(t *testing.T) {
|
||||
|
||||
// Compare want and got
|
||||
switch tt.args.format {
|
||||
case "cyclonedx":
|
||||
compareCycloneDX(t, tt.golden, outputFile)
|
||||
case "json":
|
||||
compareSBOMReports(t, tt.golden, outputFile, tt.override)
|
||||
default:
|
||||
@@ -146,8 +172,12 @@ func TestSBOM(t *testing.T) {
|
||||
func compareSBOMReports(t *testing.T, wantFile, gotFile string, overrideWant types.Report) {
|
||||
want := readReport(t, wantFile)
|
||||
|
||||
if overrideWant.ArtifactName != "" {
|
||||
want.ArtifactName = overrideWant.ArtifactName
|
||||
}
|
||||
if overrideWant.ArtifactType != "" {
|
||||
want.ArtifactType = overrideWant.ArtifactType
|
||||
}
|
||||
want.Metadata.ImageID = ""
|
||||
want.Metadata.ImageConfig = v1.ConfigFile{}
|
||||
want.Metadata.DiffIDs = nil
|
||||
|
||||
528
integration/testdata/centos-7-cyclonedx.json.golden
vendored
528
integration/testdata/centos-7-cyclonedx.json.golden
vendored
@@ -1,528 +0,0 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.4",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2023-05-19T10:38:43+00:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "aquasecurity",
|
||||
"name": "trivy",
|
||||
"version": "dev"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
"bom-ref": "urn:uuid:1455c02d-64ca-453e-a5df-ddfb70a7c804/1",
|
||||
"type": "container",
|
||||
"name": "integration/testdata/fixtures/images/centos-7.tar.gz"
|
||||
}
|
||||
},
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2019-18276",
|
||||
"ratings": [
|
||||
{
|
||||
"source": {
|
||||
"name": "cbl-mariner"
|
||||
},
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 7.2,
|
||||
"severity": "high",
|
||||
"method": "CVSSv2",
|
||||
"vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 7.8,
|
||||
"severity": "high",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "oracle-oval"
|
||||
},
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "photon"
|
||||
},
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "redhat"
|
||||
},
|
||||
"score": 7.8,
|
||||
"severity": "low",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "ubuntu"
|
||||
},
|
||||
"severity": "low"
|
||||
}
|
||||
],
|
||||
"cwes": [
|
||||
273
|
||||
],
|
||||
"description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.",
|
||||
"advisories": [
|
||||
{
|
||||
"url": "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/security/cve/CVE-2019-18276"
|
||||
},
|
||||
{
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/cve/CVE-2019-18276.html"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/errata/ELSA-2021-1679.html"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E"
|
||||
},
|
||||
{
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-18276"
|
||||
},
|
||||
{
|
||||
"url": "https://security.gentoo.org/glsa/202105-34"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20200430-0003/"
|
||||
},
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=-wGtxJ8opa8"
|
||||
}
|
||||
],
|
||||
"published": "2019-11-28T01:15:00+00:00",
|
||||
"updated": "2021-05-26T12:15:00+00:00",
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:1455c02d-64ca-453e-a5df-ddfb70a7c804/1#pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64\u0026distro=centos-7.6.1810",
|
||||
"versions": [
|
||||
{
|
||||
"version": "4.2.46-31.el7",
|
||||
"status": "affected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2019-1559",
|
||||
"ratings": [
|
||||
{
|
||||
"source": {
|
||||
"name": "amazon"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "arch-linux"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 4.3,
|
||||
"severity": "medium",
|
||||
"method": "CVSSv2",
|
||||
"vector": "AV:N/AC:M/Au:N/C:P/I:N/A:N"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 5.9,
|
||||
"severity": "medium",
|
||||
"method": "CVSSv3",
|
||||
"vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "oracle-oval"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "redhat"
|
||||
},
|
||||
"score": 5.9,
|
||||
"severity": "medium",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "ubuntu"
|
||||
},
|
||||
"severity": "medium"
|
||||
}
|
||||
],
|
||||
"cwes": [
|
||||
203
|
||||
],
|
||||
"description": "If an application encounters a fatal protocol error and then calls SSL_shutdown() twice (once to send a close_notify, and once to receive one) then OpenSSL can respond differently to the calling application if a 0 byte record is received with invalid padding compared to if a 0 byte record is received with an invalid MAC. If the application then behaves differently based on that in a way that is detectable to the remote peer, then this amounts to a padding oracle that could be used to decrypt data. In order for this to be exploitable \"non-stitched\" ciphersuites must be in use. Stitched ciphersuites are optimised implementations of certain commonly used ciphersuites. Also the application must call SSL_shutdown() twice even if a protocol error has occurred (applications should not do this but some do anyway). Fixed in OpenSSL 1.0.2r (Affected 1.0.2-1.0.2q).",
|
||||
"recommendation": "Upgrade openssl-libs to version 1:1.0.2k-19.el7",
|
||||
"advisories": [
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-03/msg00041.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00019.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00046.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00047.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-05/msg00049.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00080.html"
|
||||
},
|
||||
{
|
||||
"url": "http://www.securityfocus.com/bid/107174"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:2304"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:2437"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:2439"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:2471"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:3929"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:3931"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/security/cve/CVE-2019-1559"
|
||||
},
|
||||
{
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1559"
|
||||
},
|
||||
{
|
||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=e9bbefbf0f24c57645e7ad6a5a71ae649d18ac8e"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/RUB-NDS/TLS-Padding-Oracles"
|
||||
},
|
||||
{
|
||||
"url": "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10282"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/cve/CVE-2019-1559.html"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/errata/ELSA-2019-2471.html"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.debian.org/debian-lts-announce/2019/03/msg00003.html"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EWC42UXL5GHTU5G77VKBF6JYUUNGSHOM/"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y3IVFGSERAZLNJCK35TEM2R4726XIH3Z/"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZBEV5QGDRFUZDMNECFXUSN5FMYOZDE4V/"
|
||||
},
|
||||
{
|
||||
"url": "https://security.gentoo.org/glsa/201903-10"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20190301-0001/"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20190301-0002/"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20190423-0002/"
|
||||
},
|
||||
{
|
||||
"url": "https://support.f5.com/csp/article/K18549143"
|
||||
},
|
||||
{
|
||||
"url": "https://support.f5.com/csp/article/K18549143?utm_source=f5support\u0026amp;utm_medium=RSS"
|
||||
},
|
||||
{
|
||||
"url": "https://ubuntu.com/security/notices/USN-3899-1"
|
||||
},
|
||||
{
|
||||
"url": "https://ubuntu.com/security/notices/USN-4376-2"
|
||||
},
|
||||
{
|
||||
"url": "https://usn.ubuntu.com/3899-1/"
|
||||
},
|
||||
{
|
||||
"url": "https://usn.ubuntu.com/4376-2/"
|
||||
},
|
||||
{
|
||||
"url": "https://www.debian.org/security/2019/dsa-4400"
|
||||
},
|
||||
{
|
||||
"url": "https://www.openssl.org/news/secadv/20190226.txt"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/security-alerts/cpujan2020.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/security-alerts/cpujan2021.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.tenable.com/security/tns-2019-02"
|
||||
},
|
||||
{
|
||||
"url": "https://www.tenable.com/security/tns-2019-03"
|
||||
}
|
||||
],
|
||||
"published": "2019-02-27T23:29:00+00:00",
|
||||
"updated": "2021-01-20T15:15:00+00:00",
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:1455c02d-64ca-453e-a5df-ddfb70a7c804/1#pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026epoch=1\u0026distro=centos-7.6.1810",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1:1.0.2k-16.el7",
|
||||
"status": "affected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2018-0734",
|
||||
"ratings": [
|
||||
{
|
||||
"source": {
|
||||
"name": "amazon"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "arch-linux"
|
||||
},
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "cbl-mariner"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 4.3,
|
||||
"severity": "medium",
|
||||
"method": "CVSSv2",
|
||||
"vector": "AV:N/AC:M/Au:N/C:P/I:N/A:N"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 5.9,
|
||||
"severity": "medium",
|
||||
"method": "CVSSv3",
|
||||
"vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "oracle-oval"
|
||||
},
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "photon"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "redhat"
|
||||
},
|
||||
"score": 5.1,
|
||||
"severity": "low",
|
||||
"method": "CVSSv3",
|
||||
"vector": "CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "ubuntu"
|
||||
},
|
||||
"severity": "low"
|
||||
}
|
||||
],
|
||||
"cwes": [
|
||||
327
|
||||
],
|
||||
"description": "The OpenSSL DSA signature algorithm has been shown to be vulnerable to a timing side channel attack. An attacker could use variations in the signing algorithm to recover the private key. Fixed in OpenSSL 1.1.1a (Affected 1.1.1). Fixed in OpenSSL 1.1.0j (Affected 1.1.0-1.1.0i). Fixed in OpenSSL 1.0.2q (Affected 1.0.2-1.0.2p).",
|
||||
"recommendation": "Upgrade openssl-libs to version 1:1.0.2k-19.el7",
|
||||
"advisories": [
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00030.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-07/msg00056.html"
|
||||
},
|
||||
{
|
||||
"url": "http://www.securityfocus.com/bid/105758"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:2304"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:3700"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:3932"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:3933"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/errata/RHSA-2019:3935"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/security/cve/CVE-2018-0734"
|
||||
},
|
||||
{
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0734"
|
||||
},
|
||||
{
|
||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=43e6a58d4991a451daf4891ff05a48735df871ac"
|
||||
},
|
||||
{
|
||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=8abfe72e8c1de1b95f50aa0d9134803b4d00070f"
|
||||
},
|
||||
{
|
||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ef11e19d1365eea2b1851e6f540a0bf365d303e7"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/cve/CVE-2018-0734.html"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/errata/ELSA-2019-3700.html"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EWC42UXL5GHTU5G77VKBF6JYUUNGSHOM/"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y3IVFGSERAZLNJCK35TEM2R4726XIH3Z/"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZBEV5QGDRFUZDMNECFXUSN5FMYOZDE4V/"
|
||||
},
|
||||
{
|
||||
"url": "https://nodejs.org/en/blog/vulnerability/november-2018-security-releases/"
|
||||
},
|
||||
{
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-0734"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20181105-0002/"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20190118-0002/"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20190423-0002/"
|
||||
},
|
||||
{
|
||||
"url": "https://ubuntu.com/security/notices/USN-3840-1"
|
||||
},
|
||||
{
|
||||
"url": "https://usn.ubuntu.com/3840-1/"
|
||||
},
|
||||
{
|
||||
"url": "https://www.debian.org/security/2018/dsa-4348"
|
||||
},
|
||||
{
|
||||
"url": "https://www.debian.org/security/2018/dsa-4355"
|
||||
},
|
||||
{
|
||||
"url": "https://www.openssl.org/news/secadv/20181030.txt"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/security-alerts/cpuapr2020.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/security-alerts/cpujan2020.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpujan2019-5072801.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html"
|
||||
},
|
||||
{
|
||||
"url": "https://www.tenable.com/security/tns-2018-16"
|
||||
},
|
||||
{
|
||||
"url": "https://www.tenable.com/security/tns-2018-17"
|
||||
}
|
||||
],
|
||||
"published": "2018-10-30T12:29:00+00:00",
|
||||
"updated": "2020-08-24T17:37:00+00:00",
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:1455c02d-64ca-453e-a5df-ddfb70a7c804/1#pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026epoch=1\u0026distro=centos-7.6.1810",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1:1.0.2k-16.el7",
|
||||
"status": "affected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -77,6 +77,12 @@
|
||||
"pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json",
|
||||
"pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ref": "pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json"
|
||||
},
|
||||
{
|
||||
"ref": "pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json"
|
||||
}
|
||||
],
|
||||
"vulnerabilities": []
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2N5Y2xvbmVkeC5vcmcvYm9tIiwic3ViamVjdCI6W3sibmFtZSI6ImluZGV4LmRvY2tlci5pby9saWJyYXJ5L2NlbnRvcyIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiZTY1ZjQ4OGI3NzY0YWQzNjM4ZjIzNmI3YjUxNWIzNjc4MzY5YTUxMjRjNDdiOGQzMjkxNmQ2NDg3NDE4ZWE0In19XSwicHJlZGljYXRlIjp7ImJvbUZvcm1hdCI6IkN5Y2xvbmVEWCIsImNvbXBvbmVudHMiOlt7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjRcdTAwMjZkaXN0cm89Y2VudG9zLTcuNi4xODEwIiwibGljZW5zZXMiOlt7ImV4cHJlc3Npb24iOiJHUEx2MysifV0sIm5hbWUiOiJiYXNoIiwicHJvcGVydGllcyI6W3sibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNOYW1lIiwidmFsdWUiOiJiYXNoIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1ZlcnNpb24iLCJ2YWx1ZSI6IjQuMi40NiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNSZWxlYXNlIiwidmFsdWUiOiIzMS5lbDcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWdlc3QiLCJ2YWx1ZSI6InNoYTI1NjphYzkyMDgyMDdhZGFhYzNhNDhlNTRhNGRjNmI0OWM2OWU3OGMzMDcyZDJiM2FkZDdlZmRhYmY4MTRkYjIxMzNiIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XSwicHVybCI6InBrZzpycG0vY2VudG9zL2Jhc2hANC4yLjQ2LTMxLmVsNz9hcmNoPXg4Nl82NFx1MDAyNmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJ0eXBlIjoibGlicmFyeSIsInZlcnNpb24iOiI0LjIuNDYtMzEuZWw3In0seyJib20tcmVmIjoicGtnOnJwbS9jZW50b3Mvb3BlbnNzbC1saWJzQDEuMC4yay0xNi5lbDc/YXJjaD14ODZfNjRcdTAwMjZlcG9jaD0xXHUwMDI2ZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiT3BlblNTTCJ9XSwibmFtZSI6Im9wZW5zc2wtbGlicyIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjTmFtZSIsInZhbHVlIjoib3BlbnNzbCJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNWZXJzaW9uIiwidmFsdWUiOiIxLjAuMmsifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjUmVsZWFzZSIsInZhbHVlIjoiMTYuZWw3In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY0Vwb2NoIiwidmFsdWUiOiIxIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlnZXN0IiwidmFsdWUiOiJzaGEyNTY6YWM5MjA4MjA3YWRhYWMzYTQ4ZTU0YTRkYzZiNDljNjllNzhjMzA3MmQyYjNhZGQ3ZWZkYWJmODE0ZGIyMTMzYiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZmZJRCIsInZhbHVlIjoic2hhMjU2Ojg5MTY5ZDg3ZGJlMmI3MmJhNDJiZmJiMzU3OWM5NTczMjJiYWNhMjhlMDNhMWU1NTgwNzY1NDJhMWMxYjJiNGEifV0sInB1cmwiOiJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NFx1MDAyNmVwb2NoPTFcdTAwMjZkaXN0cm89Y2VudG9zLTcuNi4xODEwIiwidHlwZSI6ImxpYnJhcnkiLCJ2ZXJzaW9uIjoiMS4wLjJrLTE2LmVsNyJ9LHsiYm9tLXJlZiI6IjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSIsIm5hbWUiOiJjZW50b3MiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlR5cGUiLCJ2YWx1ZSI6ImNlbnRvcyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpDbGFzcyIsInZhbHVlIjoib3MtcGtncyJ9XSwidHlwZSI6Im9wZXJhdGluZy1zeXN0ZW0iLCJ2ZXJzaW9uIjoiNy42LjE4MTAifV0sImRlcGVuZGVuY2llcyI6W3siZGVwZW5kc09uIjpbInBrZzpycG0vY2VudG9zL2Jhc2hANC4yLjQ2LTMxLmVsNz9hcmNoPXg4Nl82NFx1MDAyNmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NFx1MDAyNmVwb2NoPTFcdTAwMjZkaXN0cm89Y2VudG9zLTcuNi4xODEwIl0sInJlZiI6IjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSJ9LHsiZGVwZW5kc09uIjpbIjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSJdLCJyZWYiOiJkMGQ0MWUzMC05NjUwLTQ4OWQtOTQ4ZC00MjVmZjJlZDYzZDIifV0sIm1ldGFkYXRhIjp7ImNvbXBvbmVudCI6eyJib20tcmVmIjoiZDBkNDFlMzAtOTY1MC00ODlkLTk0OGQtNDI1ZmYyZWQ2M2QyIiwibmFtZSI6ImludGVncmF0aW9uL3Rlc3RkYXRhL2ZpeHR1cmVzL2ltYWdlcy9jZW50b3MtNy50YXIuZ3oiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNjaGVtYVZlcnNpb24iLCJ2YWx1ZSI6IjIifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6SW1hZ2VJRCIsInZhbHVlIjoic2hhMjU2OmYxY2I3YzdkNThiNzNlYWM4NTljMzk1ODgyZWVjNDlkNTA2NTEyNDRlMzQyY2Q2YzY4YTVjNzgwOTc4NWY0MjcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6RGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XSwidHlwZSI6ImNvbnRhaW5lciJ9LCJ0aW1lc3RhbXAiOiIyMDIyLTA2LTE0VDE1OjA4OjQ4KzAwOjAwIiwidG9vbHMiOlt7Im5hbWUiOiJ0cml2eSIsInZlbmRvciI6ImFxdWFzZWN1cml0eSIsInZlcnNpb24iOiJkZXYifV19LCJzZXJpYWxOdW1iZXIiOiJ1cm46dXVpZDoxNDU1YzAyZC02NGNhLTQ1M2UtYTVkZi1kZGZiNzBhN2M4MDQiLCJzcGVjVmVyc2lvbiI6IjEuNCIsInZlcnNpb24iOjF9fQ==","signatures":[{"keyid":"","sig":"MEUCIQCtj78dipe+yzdlIsmwjn9QeaBTAPQacwIJAWfnrtp7FwIgcViOUgPA0WFYjimrIl7vbygdSpduM+ZzY3cqrDciH1U="}]}
|
||||
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2N5Y2xvbmVkeC5vcmcvYm9tIiwic3ViamVjdCI6W3sibmFtZSI6ImluZGV4LmRvY2tlci5pby9saWJyYXJ5L2NlbnRvcyIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiZTY1ZjQ4OGI3NzY0YWQzNjM4ZjIzNmI3YjUxNWIzNjc4MzY5YTUxMjRjNDdiOGQzMjkxNmQ2NDg3NDE4ZWE0In19XSwicHJlZGljYXRlIjp7ImJvbUZvcm1hdCI6IkN5Y2xvbmVEWCIsInNwZWNWZXJzaW9uIjoiMS40Iiwic2VyaWFsTnVtYmVyIjoidXJuOnV1aWQ6MTQ1NWMwMmQtNjRjYS00NTNlLWE1ZGYtZGRmYjcwYTdjODA0IiwidmVyc2lvbiI6MSwibWV0YWRhdGEiOnsidGltZXN0YW1wIjoiMjAyMi0wNi0xNFQxNTowODo0OCswMDowMCIsInRvb2xzIjpbeyJ2ZW5kb3IiOiJhcXVhc2VjdXJpdHkiLCJuYW1lIjoidHJpdnkiLCJ2ZXJzaW9uIjoiZGV2In1dLCJjb21wb25lbnQiOnsiYm9tLXJlZiI6ImQwZDQxZTMwLTk2NTAtNDg5ZC05NDhkLTQyNWZmMmVkNjNkMiIsInR5cGUiOiJjb250YWluZXIiLCJuYW1lIjoiaW50ZWdyYXRpb24vdGVzdGRhdGEvZml4dHVyZXMvaW1hZ2VzL2NlbnRvcy03LnRhci5neiIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U2NoZW1hVmVyc2lvbiIsInZhbHVlIjoiMiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpJbWFnZUlEIiwidmFsdWUiOiJzaGEyNTY6ZjFjYjdjN2Q1OGI3M2VhYzg1OWMzOTU4ODJlZWM0OWQ1MDY1MTI0NGUzNDJjZDZjNjhhNWM3ODA5Nzg1ZjQyNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn1dfX0sImNvbXBvbmVudHMiOlt7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjQmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInR5cGUiOiJsaWJyYXJ5IiwibmFtZSI6ImJhc2giLCJ2ZXJzaW9uIjoiNC4yLjQ2LTMxLmVsNyIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiR1BMdjMrIn1dLCJwdXJsIjoicGtnOnJwbS9jZW50b3MvYmFzaEA0LjIuNDYtMzEuZWw3P2FyY2g9eDg2XzY0JmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlBrZ0lEIiwidmFsdWUiOiJiYXNoQDQuMi40Ni0zMS5lbDcueDg2XzY0In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY05hbWUiLCJ2YWx1ZSI6ImJhc2gifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjVmVyc2lvbiIsInZhbHVlIjoiNC4yLjQ2In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1JlbGVhc2UiLCJ2YWx1ZSI6IjMxLmVsNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZ2VzdCIsInZhbHVlIjoic2hhMjU2OmFjOTIwODIwN2FkYWFjM2E0OGU1NGE0ZGM2YjQ5YzY5ZTc4YzMwNzJkMmIzYWRkN2VmZGFiZjgxNGRiMjEzM2IifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn1dfSx7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NCZlcG9jaD0xJmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJ0eXBlIjoibGlicmFyeSIsIm5hbWUiOiJvcGVuc3NsLWxpYnMiLCJ2ZXJzaW9uIjoiMS4wLjJrLTE2LmVsNyIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiT3BlblNTTCJ9XSwicHVybCI6InBrZzpycG0vY2VudG9zL29wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3P2FyY2g9eDg2XzY0JmVwb2NoPTEmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6UGtnSUQiLCJ2YWx1ZSI6Im9wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3Lng4Nl82NCJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNOYW1lIiwidmFsdWUiOiJvcGVuc3NsIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1ZlcnNpb24iLCJ2YWx1ZSI6IjEuMC4yayJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNSZWxlYXNlIiwidmFsdWUiOiIxNi5lbDcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjRXBvY2giLCJ2YWx1ZSI6IjEifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWdlc3QiLCJ2YWx1ZSI6InNoYTI1NjphYzkyMDgyMDdhZGFhYzNhNDhlNTRhNGRjNmI0OWM2OWU3OGMzMDcyZDJiM2FkZDdlZmRhYmY4MTRkYjIxMzNiIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XX0seyJib20tcmVmIjoiMDE3NWY3MzItZGY5ZC00YmI4LTlmNTYtODcwODk4ZTNmZjg5IiwidHlwZSI6Im9wZXJhdGluZy1zeXN0ZW0iLCJuYW1lIjoiY2VudG9zIiwidmVyc2lvbiI6IjcuNi4xODEwIiwicHJvcGVydGllcyI6W3sibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpUeXBlIiwidmFsdWUiOiJjZW50b3MifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6Q2xhc3MiLCJ2YWx1ZSI6Im9zLXBrZ3MifV19XSwiZGVwZW5kZW5jaWVzIjpbeyJyZWYiOiIwMTc1ZjczMi1kZjlkLTRiYjgtOWY1Ni04NzA4OThlM2ZmODkiLCJkZXBlbmRzT24iOlsicGtnOnJwbS9jZW50b3MvYmFzaEA0LjIuNDYtMzEuZWw3P2FyY2g9eDg2XzY0JmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NCZlcG9jaD0xJmRpc3Rybz1jZW50b3MtNy42LjE4MTAiXX0seyJyZWYiOiJkMGQ0MWUzMC05NjUwLTQ4OWQtOTQ4ZC00MjVmZjJlZDYzZDIiLCJkZXBlbmRzT24iOlsiMDE3NWY3MzItZGY5ZC00YmI4LTlmNTYtODcwODk4ZTNmZjg5Il19XX19Cg==","signatures":[{"keyid":"","sig":"MEUCIQCtj78dipe+yzdlIsmwjn9QeaBTAPQacwIJAWfnrtp7FwIgcViOUgPA0WFYjimrIl7vbygdSpduM+ZzY3cqrDciH1U="}]}
|
||||
|
||||
@@ -45,6 +45,10 @@
|
||||
],
|
||||
"purl": "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "bash@4.2.46-31.el7.x86_64"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:SrcName",
|
||||
"value": "bash"
|
||||
@@ -79,6 +83,10 @@
|
||||
],
|
||||
"purl": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810",
|
||||
"properties": [
|
||||
{
|
||||
"name": "aquasecurity:trivy:PkgID",
|
||||
"value": "openssl-libs@1.0.2k-16.el7.x86_64"
|
||||
},
|
||||
{
|
||||
"name": "aquasecurity:trivy:SrcName",
|
||||
"value": "openssl"
|
||||
|
||||
@@ -1,346 +1,187 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.4",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2023-05-19T10:38:42+00:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "aquasecurity",
|
||||
"name": "trivy",
|
||||
"version": "dev"
|
||||
"SchemaVersion": 2,
|
||||
"ArtifactName": "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
|
||||
"ArtifactType": "cyclonedx",
|
||||
"Metadata": {
|
||||
"OS": {
|
||||
"Family": "debian",
|
||||
"Name": "10.2"
|
||||
},
|
||||
"ImageConfig": {
|
||||
"architecture": "",
|
||||
"created": "0001-01-01T00:00:00Z",
|
||||
"os": "",
|
||||
"rootfs": {
|
||||
"type": "",
|
||||
"diff_ids": null
|
||||
},
|
||||
"config": {}
|
||||
}
|
||||
},
|
||||
"Results": [
|
||||
{
|
||||
"Target": "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json (debian 10.2)",
|
||||
"Class": "os-pkgs",
|
||||
"Type": "debian",
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"VulnerabilityID": "CVE-2019-18276",
|
||||
"PkgName": "bash",
|
||||
"InstalledVersion": "5.0-4",
|
||||
"Layer": {},
|
||||
"SeveritySource": "debian",
|
||||
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-18276",
|
||||
"PkgRef": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2",
|
||||
"DataSource": {
|
||||
"ID": "debian",
|
||||
"Name": "Debian Security Tracker",
|
||||
"URL": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
||||
},
|
||||
"Title": "bash: when effective UID is not equal to its real UID the saved UID is not dropped",
|
||||
"Description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.",
|
||||
"Severity": "LOW",
|
||||
"CweIDs": [
|
||||
"CWE-273"
|
||||
],
|
||||
"component": {
|
||||
"bom-ref": "urn:uuid:31ee662c-480e-4f63-9765-23ea8afc754d/1",
|
||||
"type": "container",
|
||||
"name": "integration/testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz"
|
||||
"CVSS": {
|
||||
"nvd": {
|
||||
"V2Vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C",
|
||||
"V3Vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
|
||||
"V2Score": 7.2,
|
||||
"V3Score": 7.8
|
||||
},
|
||||
"redhat": {
|
||||
"V3Vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
|
||||
"V3Score": 7.8
|
||||
}
|
||||
},
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2020-8165",
|
||||
"source": {
|
||||
"name": "ghsa",
|
||||
"url": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems"
|
||||
},
|
||||
"ratings": [
|
||||
{
|
||||
"source": {
|
||||
"name": "ghsa"
|
||||
},
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 7.5,
|
||||
"severity": "high",
|
||||
"method": "CVSSv2",
|
||||
"vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 9.8,
|
||||
"severity": "critical",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "redhat"
|
||||
},
|
||||
"score": 9.8,
|
||||
"severity": "high",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
||||
}
|
||||
"References": [
|
||||
"http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html",
|
||||
"https://access.redhat.com/security/cve/CVE-2019-18276",
|
||||
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276",
|
||||
"https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff",
|
||||
"https://linux.oracle.com/cve/CVE-2019-18276.html",
|
||||
"https://linux.oracle.com/errata/ELSA-2021-1679.html",
|
||||
"https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E",
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2019-18276",
|
||||
"https://security.gentoo.org/glsa/202105-34",
|
||||
"https://security.netapp.com/advisory/ntap-20200430-0003/",
|
||||
"https://www.youtube.com/watch?v=-wGtxJ8opa8"
|
||||
],
|
||||
"cwes": [
|
||||
502
|
||||
"PublishedDate": "2019-11-28T01:15:00Z",
|
||||
"LastModifiedDate": "2021-05-26T12:15:00Z"
|
||||
},
|
||||
{
|
||||
"VulnerabilityID": "CVE-2019-18224",
|
||||
"VendorIDs": [
|
||||
"DSA-4613-1"
|
||||
],
|
||||
"description": "A deserialization of untrusted data vulnerability exists in rails \u003c 5.2.4.3, rails \u003c 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.",
|
||||
"recommendation": "Upgrade activesupport to version 6.0.3.1, 5.2.4.3",
|
||||
"advisories": [
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00031.html"
|
||||
"PkgName": "libidn2-0",
|
||||
"InstalledVersion": "2.0.5-1",
|
||||
"FixedVersion": "2.0.5-1+deb10u1",
|
||||
"Layer": {},
|
||||
"SeveritySource": "nvd",
|
||||
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-18224",
|
||||
"PkgRef": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2",
|
||||
"DataSource": {
|
||||
"ID": "debian",
|
||||
"Name": "Debian Security Tracker",
|
||||
"URL": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00034.html"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/security/cve/CVE-2020-8165"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/advisories/GHSA-2p68-f74v-9wc6"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2020-8165.yml"
|
||||
},
|
||||
{
|
||||
"url": "https://groups.google.com/forum/#!msg/rubyonrails-security/bv6fW4S0Y1c/KnkEqM7AAQAJ"
|
||||
},
|
||||
{
|
||||
"url": "https://groups.google.com/forum/#!topic/rubyonrails-security/bv6fW4S0Y1c"
|
||||
},
|
||||
{
|
||||
"url": "https://groups.google.com/g/rubyonrails-security/c/bv6fW4S0Y1c"
|
||||
},
|
||||
{
|
||||
"url": "https://hackerone.com/reports/413388"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.debian.org/debian-lts-announce/2020/06/msg00022.html"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.debian.org/debian-lts-announce/2020/07/msg00013.html"
|
||||
},
|
||||
{
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-8165"
|
||||
},
|
||||
{
|
||||
"url": "https://weblog.rubyonrails.org/2020/5/18/Rails-5-2-4-3-and-6-0-3-1-have-been-released/"
|
||||
},
|
||||
{
|
||||
"url": "https://www.debian.org/security/2020/dsa-4766"
|
||||
}
|
||||
"Title": "libidn2: heap-based buffer overflow in idn2_to_ascii_4i in lib/lookup.c",
|
||||
"Description": "idn2_to_ascii_4i in lib/lookup.c in GNU libidn2 before 2.1.1 has a heap-based buffer overflow via a long domain string.",
|
||||
"Severity": "CRITICAL",
|
||||
"CweIDs": [
|
||||
"CWE-787"
|
||||
],
|
||||
"published": "2020-06-19T18:15:00+00:00",
|
||||
"updated": "2020-10-17T12:15:00+00:00",
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:31ee662c-480e-4f63-9765-23ea8afc754d/1#pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec",
|
||||
"versions": [
|
||||
{
|
||||
"version": "6.0.2.1",
|
||||
"status": "affected"
|
||||
"CVSS": {
|
||||
"nvd": {
|
||||
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"V2Score": 7.5,
|
||||
"V3Score": 9.8
|
||||
},
|
||||
"redhat": {
|
||||
"V3Vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||
"V3Score": 5.6
|
||||
}
|
||||
]
|
||||
},
|
||||
"References": [
|
||||
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00008.html",
|
||||
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html",
|
||||
"https://access.redhat.com/security/cve/CVE-2019-18224",
|
||||
"https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=12420",
|
||||
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18224",
|
||||
"https://github.com/libidn/libidn2/commit/e4d1558aa2c1c04a05066ee8600f37603890ba8c",
|
||||
"https://github.com/libidn/libidn2/compare/libidn2-2.1.0...libidn2-2.1.1",
|
||||
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JDQVQ2XPV5BTZUFINT7AFJSKNNBVURNJ/",
|
||||
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MINU5RKDFE6TKAFY5DRFN3WSFDS4DYVS/",
|
||||
"https://seclists.org/bugtraq/2020/Feb/4",
|
||||
"https://security.gentoo.org/glsa/202003-63",
|
||||
"https://ubuntu.com/security/notices/USN-4168-1",
|
||||
"https://usn.ubuntu.com/4168-1/",
|
||||
"https://www.debian.org/security/2020/dsa-4613"
|
||||
],
|
||||
"PublishedDate": "2019-10-21T17:15:00Z",
|
||||
"LastModifiedDate": "2019-10-29T19:15:00Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2019-18276",
|
||||
"source": {
|
||||
"name": "debian",
|
||||
"url": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
||||
},
|
||||
"ratings": [
|
||||
"Target": "Ruby",
|
||||
"Class": "lang-pkgs",
|
||||
"Type": "gemspec",
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"source": {
|
||||
"name": "cbl-mariner"
|
||||
"VulnerabilityID": "CVE-2020-8165",
|
||||
"PkgName": "activesupport",
|
||||
"InstalledVersion": "6.0.2.1",
|
||||
"FixedVersion": "6.0.3.1, 5.2.4.3",
|
||||
"Layer": {},
|
||||
"SeveritySource": "ghsa",
|
||||
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-8165",
|
||||
"PkgRef": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec",
|
||||
"DataSource": {
|
||||
"ID": "ghsa",
|
||||
"Name": "GitHub Security Advisory RubyGems",
|
||||
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems"
|
||||
},
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 7.2,
|
||||
"severity": "high",
|
||||
"method": "CVSSv2",
|
||||
"vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 7.8,
|
||||
"severity": "high",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "oracle-oval"
|
||||
},
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "photon"
|
||||
},
|
||||
"severity": "high"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "redhat"
|
||||
},
|
||||
"score": 7.8,
|
||||
"severity": "low",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "ubuntu"
|
||||
},
|
||||
"severity": "low"
|
||||
}
|
||||
"Title": "rubygem-activesupport: potentially unintended unmarshalling of user-provided objects in MemCacheStore and RedisCacheStore",
|
||||
"Description": "A deserialization of untrusted data vulnerability exists in rails \u003c 5.2.4.3, rails \u003c 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.",
|
||||
"Severity": "HIGH",
|
||||
"CweIDs": [
|
||||
"CWE-502"
|
||||
],
|
||||
"cwes": [
|
||||
273
|
||||
"CVSS": {
|
||||
"nvd": {
|
||||
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"V2Score": 7.5,
|
||||
"V3Score": 9.8
|
||||
},
|
||||
"redhat": {
|
||||
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"V3Score": 9.8
|
||||
}
|
||||
},
|
||||
"References": [
|
||||
"http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00031.html",
|
||||
"http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00034.html",
|
||||
"https://access.redhat.com/security/cve/CVE-2020-8165",
|
||||
"https://github.com/advisories/GHSA-2p68-f74v-9wc6",
|
||||
"https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2020-8165.yml",
|
||||
"https://groups.google.com/forum/#!msg/rubyonrails-security/bv6fW4S0Y1c/KnkEqM7AAQAJ",
|
||||
"https://groups.google.com/forum/#!topic/rubyonrails-security/bv6fW4S0Y1c",
|
||||
"https://groups.google.com/g/rubyonrails-security/c/bv6fW4S0Y1c",
|
||||
"https://hackerone.com/reports/413388",
|
||||
"https://lists.debian.org/debian-lts-announce/2020/06/msg00022.html",
|
||||
"https://lists.debian.org/debian-lts-announce/2020/07/msg00013.html",
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2020-8165",
|
||||
"https://weblog.rubyonrails.org/2020/5/18/Rails-5-2-4-3-and-6-0-3-1-have-been-released/",
|
||||
"https://www.debian.org/security/2020/dsa-4766"
|
||||
],
|
||||
"description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.",
|
||||
"advisories": [
|
||||
{
|
||||
"url": "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/security/cve/CVE-2019-18276"
|
||||
},
|
||||
{
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/cve/CVE-2019-18276.html"
|
||||
},
|
||||
{
|
||||
"url": "https://linux.oracle.com/errata/ELSA-2021-1679.html"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E"
|
||||
},
|
||||
{
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-18276"
|
||||
},
|
||||
{
|
||||
"url": "https://security.gentoo.org/glsa/202105-34"
|
||||
},
|
||||
{
|
||||
"url": "https://security.netapp.com/advisory/ntap-20200430-0003/"
|
||||
},
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=-wGtxJ8opa8"
|
||||
}
|
||||
],
|
||||
"published": "2019-11-28T01:15:00+00:00",
|
||||
"updated": "2021-05-26T12:15:00+00:00",
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:31ee662c-480e-4f63-9765-23ea8afc754d/1#pkg:deb/debian/bash@5.0-4?distro=debian-10.2",
|
||||
"versions": [
|
||||
{
|
||||
"version": "5.0-4",
|
||||
"status": "affected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2019-18224",
|
||||
"source": {
|
||||
"name": "debian",
|
||||
"url": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
||||
},
|
||||
"ratings": [
|
||||
{
|
||||
"source": {
|
||||
"name": "amazon"
|
||||
},
|
||||
"severity": "medium"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 7.5,
|
||||
"severity": "high",
|
||||
"method": "CVSSv2",
|
||||
"vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "nvd"
|
||||
},
|
||||
"score": 9.8,
|
||||
"severity": "critical",
|
||||
"method": "CVSSv31",
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "redhat"
|
||||
},
|
||||
"score": 5.6,
|
||||
"severity": "medium",
|
||||
"method": "CVSSv3",
|
||||
"vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L"
|
||||
},
|
||||
{
|
||||
"source": {
|
||||
"name": "ubuntu"
|
||||
},
|
||||
"severity": "medium"
|
||||
}
|
||||
],
|
||||
"cwes": [
|
||||
787
|
||||
],
|
||||
"description": "idn2_to_ascii_4i in lib/lookup.c in GNU libidn2 before 2.1.1 has a heap-based buffer overflow via a long domain string.",
|
||||
"recommendation": "Upgrade libidn2-0 to version 2.0.5-1+deb10u1",
|
||||
"advisories": [
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00008.html"
|
||||
},
|
||||
{
|
||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html"
|
||||
},
|
||||
{
|
||||
"url": "https://access.redhat.com/security/cve/CVE-2019-18224"
|
||||
},
|
||||
{
|
||||
"url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=12420"
|
||||
},
|
||||
{
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18224"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/libidn/libidn2/commit/e4d1558aa2c1c04a05066ee8600f37603890ba8c"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/libidn/libidn2/compare/libidn2-2.1.0...libidn2-2.1.1"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JDQVQ2XPV5BTZUFINT7AFJSKNNBVURNJ/"
|
||||
},
|
||||
{
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MINU5RKDFE6TKAFY5DRFN3WSFDS4DYVS/"
|
||||
},
|
||||
{
|
||||
"url": "https://seclists.org/bugtraq/2020/Feb/4"
|
||||
},
|
||||
{
|
||||
"url": "https://security.gentoo.org/glsa/202003-63"
|
||||
},
|
||||
{
|
||||
"url": "https://ubuntu.com/security/notices/USN-4168-1"
|
||||
},
|
||||
{
|
||||
"url": "https://usn.ubuntu.com/4168-1/"
|
||||
},
|
||||
{
|
||||
"url": "https://www.debian.org/security/2020/dsa-4613"
|
||||
}
|
||||
],
|
||||
"published": "2019-10-21T17:15:00+00:00",
|
||||
"updated": "2019-10-29T19:15:00+00:00",
|
||||
"affects": [
|
||||
{
|
||||
"ref": "urn:cdx:31ee662c-480e-4f63-9765-23ea8afc754d/1#pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2",
|
||||
"versions": [
|
||||
{
|
||||
"version": "2.0.5-1",
|
||||
"status": "affected"
|
||||
}
|
||||
]
|
||||
"PublishedDate": "2020-06-19T18:15:00Z",
|
||||
"LastModifiedDate": "2020-10-17T12:15:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1110,9 +1110,6 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||
Example: ` # Scan CycloneDX and show the result in tables
|
||||
$ trivy sbom /path/to/report.cdx
|
||||
|
||||
# Scan CycloneDX and generate a CycloneDX report
|
||||
$ trivy sbom --format cyclonedx /path/to/report.cdx
|
||||
|
||||
# Scan CycloneDX-type attestation and show the result in tables
|
||||
$ trivy sbom /path/to/report.cdx.intoto.jsonl
|
||||
`,
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
@@ -29,18 +27,7 @@ func NewWriter(output io.Writer, appVersion string) Writer {
|
||||
|
||||
// Write writes the results in CycloneDX format
|
||||
func (w Writer) Write(report types.Report) error {
|
||||
var bom *cdx.BOM
|
||||
var err error
|
||||
|
||||
// When the input is CycloneDX, only vulnerabilities will be stored in CycloneDX.
|
||||
// Each vulnerability has a reference to a component in the original CycloneDX.
|
||||
// e.g. "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#jackson-databind-2.8.0"
|
||||
if report.ArtifactType == ftypes.ArtifactCycloneDX {
|
||||
log.Logger.Info("Components will not be exported in the CycloneDX report as the input is CycloneDX")
|
||||
bom, err = w.marshaler.MarshalVulnerabilities(report)
|
||||
} else {
|
||||
bom, err = w.marshaler.Marshal(report)
|
||||
}
|
||||
bom, err := w.marshaler.Marshal(report)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("CycloneDX marshal error: %w", err)
|
||||
}
|
||||
|
||||
489
pkg/sbom/cyclonedx/core/cyclonedx.go
Normal file
489
pkg/sbom/cyclonedx/core/cyclonedx.go
Normal file
@@ -0,0 +1,489 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||
"github.com/google/uuid"
|
||||
"github.com/samber/lo"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
dtypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||
"github.com/aquasecurity/trivy/pkg/digest"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/purl"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
const (
|
||||
ToolVendor = "aquasecurity"
|
||||
ToolName = "trivy"
|
||||
Namespace = ToolVendor + ":" + ToolName + ":"
|
||||
|
||||
// https://json-schema.org/understanding-json-schema/reference/string.html#dates-and-times
|
||||
timeLayout = "2006-01-02T15:04:05+00:00"
|
||||
)
|
||||
|
||||
type NewUUID func() uuid.UUID
|
||||
|
||||
type Option func(dx *CycloneDX)
|
||||
|
||||
func WithClock(clock clock.Clock) Option {
|
||||
return func(opts *CycloneDX) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
func WithNewUUID(newUUID NewUUID) Option {
|
||||
return func(opts *CycloneDX) {
|
||||
opts.newUUID = newUUID
|
||||
}
|
||||
}
|
||||
|
||||
type CycloneDX struct {
|
||||
appVersion string
|
||||
clock clock.Clock
|
||||
newUUID NewUUID
|
||||
}
|
||||
|
||||
type Component struct {
|
||||
Type cdx.ComponentType
|
||||
Name string
|
||||
Version string
|
||||
PackageURL *purl.PackageURL
|
||||
Licenses []string
|
||||
Hashes []digest.Digest
|
||||
Supplier string
|
||||
Properties map[string]string
|
||||
|
||||
Components []*Component
|
||||
Vulnerabilities []types.DetectedVulnerability
|
||||
}
|
||||
|
||||
func NewCycloneDX(version string, opts ...Option) *CycloneDX {
|
||||
c := &CycloneDX{
|
||||
appVersion: version,
|
||||
clock: clock.RealClock{},
|
||||
newUUID: uuid.New,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Marshal(root *Component) *cdx.BOM {
|
||||
bom := cdx.NewBOM()
|
||||
bom.SerialNumber = c.newUUID().URN()
|
||||
bom.Metadata = c.Metadata()
|
||||
|
||||
components := map[string]*cdx.Component{}
|
||||
dependencies := map[string]*[]string{}
|
||||
vulnerabilities := map[string]*cdx.Vulnerability{}
|
||||
bom.Metadata.Component = c.MarshalComponent(root, components, dependencies, vulnerabilities)
|
||||
|
||||
// Remove metadata component
|
||||
delete(components, bom.Metadata.Component.BOMRef)
|
||||
|
||||
bom.Components = c.Components(components)
|
||||
bom.Dependencies = c.Dependencies(dependencies)
|
||||
bom.Vulnerabilities = c.Vulnerabilities(vulnerabilities)
|
||||
|
||||
return bom
|
||||
}
|
||||
|
||||
func (c *CycloneDX) MarshalComponent(component *Component, components map[string]*cdx.Component,
|
||||
deps map[string]*[]string, vulns map[string]*cdx.Vulnerability) *cdx.Component {
|
||||
bomRef := c.BOMRef(component)
|
||||
|
||||
// When multiple lock files have the same dependency with the same name and version,
|
||||
// "BOM-Ref" (PURL technically) of "Library" components may conflict.
|
||||
// In that case, only one "Library" component will be added and
|
||||
// some "Application" components will refer to the same component.
|
||||
// e.g.
|
||||
// Application component (/app1/package-lock.json)
|
||||
// |
|
||||
// | Application component (/app2/package-lock.json)
|
||||
// | |
|
||||
// └----┴----> Library component (npm package, express-4.17.3)
|
||||
//
|
||||
if v, ok := components[bomRef]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
cdxComponent := &cdx.Component{
|
||||
BOMRef: bomRef,
|
||||
Type: component.Type,
|
||||
Name: component.Name,
|
||||
Version: component.Version,
|
||||
PackageURL: c.PackageURL(component.PackageURL),
|
||||
Supplier: c.Supplier(component.Supplier),
|
||||
Hashes: c.Hashes(component.Hashes),
|
||||
Licenses: c.Licenses(component.Licenses),
|
||||
Properties: lo.ToPtr(c.Properties(component.Properties)),
|
||||
}
|
||||
components[cdxComponent.BOMRef] = cdxComponent
|
||||
|
||||
for _, v := range component.Vulnerabilities {
|
||||
// If the same vulnerability affects multiple packages, those packages will be aggregated into one vulnerability.
|
||||
// Vulnerability component (CVE-2020-26247)
|
||||
// -> Library component (nokogiri /srv/app1/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
||||
// -> Library component (nokogiri /srv/app2/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
||||
if vuln, ok := vulns[v.VulnerabilityID]; ok {
|
||||
*vuln.Affects = append(*vuln.Affects, cdxAffects(bomRef, v.InstalledVersion))
|
||||
} else {
|
||||
vulns[v.VulnerabilityID] = c.marshalVulnerability(cdxComponent.BOMRef, v)
|
||||
}
|
||||
}
|
||||
|
||||
var dependencies []string
|
||||
for _, child := range component.Components {
|
||||
childComponent := c.MarshalComponent(child, components, deps, vulns)
|
||||
dependencies = append(dependencies, childComponent.BOMRef)
|
||||
}
|
||||
sort.Strings(dependencies)
|
||||
|
||||
deps[cdxComponent.BOMRef] = &dependencies
|
||||
|
||||
return cdxComponent
|
||||
}
|
||||
|
||||
func (c *CycloneDX) marshalVulnerability(bomRef string, vuln types.DetectedVulnerability) *cdx.Vulnerability {
|
||||
v := &cdx.Vulnerability{
|
||||
ID: vuln.VulnerabilityID,
|
||||
Source: cdxSource(vuln.DataSource),
|
||||
Ratings: cdxRatings(vuln),
|
||||
CWEs: cwes(vuln.CweIDs),
|
||||
Description: vuln.Description,
|
||||
Advisories: cdxAdvisories(vuln.References),
|
||||
}
|
||||
if vuln.FixedVersion != "" {
|
||||
v.Recommendation = fmt.Sprintf("Upgrade %s to version %s", vuln.PkgName, vuln.FixedVersion)
|
||||
}
|
||||
if vuln.PublishedDate != nil {
|
||||
v.Published = vuln.PublishedDate.Format(timeLayout)
|
||||
}
|
||||
if vuln.LastModifiedDate != nil {
|
||||
v.Updated = vuln.LastModifiedDate.Format(timeLayout)
|
||||
}
|
||||
|
||||
v.Affects = &[]cdx.Affects{cdxAffects(bomRef, vuln.InstalledVersion)}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (c *CycloneDX) BOMRef(component *Component) string {
|
||||
// PURL takes precedence over UUID
|
||||
if component.PackageURL == nil {
|
||||
return c.newUUID().String()
|
||||
}
|
||||
return component.PackageURL.BOMRef()
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Metadata() *cdx.Metadata {
|
||||
return &cdx.Metadata{
|
||||
Timestamp: c.clock.Now().UTC().Format(timeLayout),
|
||||
Tools: &[]cdx.Tool{
|
||||
{
|
||||
Vendor: ToolVendor,
|
||||
Name: ToolName,
|
||||
Version: c.appVersion,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Components(uniq map[string]*cdx.Component) *[]cdx.Component {
|
||||
// Convert components from map to slice and sort by BOM-Ref
|
||||
components := lo.MapToSlice(uniq, func(_ string, value *cdx.Component) cdx.Component {
|
||||
return *value
|
||||
})
|
||||
sort.Slice(components, func(i, j int) bool {
|
||||
return components[i].BOMRef < components[j].BOMRef
|
||||
})
|
||||
return &components
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Dependencies(uniq map[string]*[]string) *[]cdx.Dependency {
|
||||
// Convert dependencies from map to slice and sort by BOM-Ref
|
||||
dependencies := lo.MapToSlice(uniq, func(bomRef string, value *[]string) cdx.Dependency {
|
||||
return cdx.Dependency{
|
||||
Ref: bomRef,
|
||||
Dependencies: value,
|
||||
}
|
||||
})
|
||||
sort.Slice(dependencies, func(i, j int) bool {
|
||||
return dependencies[i].Ref < dependencies[j].Ref
|
||||
})
|
||||
return &dependencies
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Vulnerabilities(uniq map[string]*cdx.Vulnerability) *[]cdx.Vulnerability {
|
||||
vulns := lo.MapToSlice(uniq, func(bomRef string, value *cdx.Vulnerability) cdx.Vulnerability {
|
||||
sort.Slice(*value.Affects, func(i, j int) bool {
|
||||
return (*value.Affects)[i].Ref < (*value.Affects)[j].Ref
|
||||
})
|
||||
return *value
|
||||
})
|
||||
sort.Slice(vulns, func(i, j int) bool {
|
||||
return vulns[i].BOMRef < vulns[j].BOMRef
|
||||
})
|
||||
return &vulns
|
||||
}
|
||||
|
||||
func (c *CycloneDX) PackageURL(purl *purl.PackageURL) string {
|
||||
if purl == nil {
|
||||
return ""
|
||||
}
|
||||
return purl.String()
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Supplier(supplier string) *cdx.OrganizationalEntity {
|
||||
if supplier == "" {
|
||||
return nil
|
||||
}
|
||||
return &cdx.OrganizationalEntity{
|
||||
Name: supplier,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Hashes(hashes []digest.Digest) *[]cdx.Hash {
|
||||
if len(hashes) == 0 {
|
||||
return nil
|
||||
}
|
||||
var cdxHashes []cdx.Hash
|
||||
for _, hash := range hashes {
|
||||
var alg cdx.HashAlgorithm
|
||||
switch hash.Algorithm() {
|
||||
case digest.SHA1:
|
||||
alg = cdx.HashAlgoSHA1
|
||||
case digest.SHA256:
|
||||
alg = cdx.HashAlgoSHA256
|
||||
case digest.MD5:
|
||||
alg = cdx.HashAlgoMD5
|
||||
default:
|
||||
log.Logger.Debugf("Unable to convert %q algorithm to CycloneDX format", hash.Algorithm())
|
||||
continue
|
||||
}
|
||||
|
||||
cdxHashes = append(cdxHashes, cdx.Hash{
|
||||
Algorithm: alg,
|
||||
Value: hash.Encoded(),
|
||||
})
|
||||
}
|
||||
return &cdxHashes
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Licenses(licenses []string) *cdx.Licenses {
|
||||
if len(licenses) == 0 {
|
||||
return nil
|
||||
}
|
||||
choices := lo.Map(licenses, func(license string, i int) cdx.LicenseChoice {
|
||||
return cdx.LicenseChoice{Expression: license}
|
||||
})
|
||||
return lo.ToPtr(cdx.Licenses(choices))
|
||||
}
|
||||
|
||||
func (c *CycloneDX) Properties(props map[string]string) []cdx.Property {
|
||||
properties := lo.MapToSlice(props, func(k, v string) cdx.Property {
|
||||
return cdx.Property{
|
||||
Name: Namespace + k,
|
||||
Value: v,
|
||||
}
|
||||
})
|
||||
sort.Slice(properties, func(i, j int) bool {
|
||||
return properties[i].Name < properties[j].Name
|
||||
})
|
||||
return properties
|
||||
}
|
||||
|
||||
func IsTrivySBOM(c *cdx.BOM) bool {
|
||||
if c == nil || c.Metadata == nil || c.Metadata.Tools == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, tool := range *c.Metadata.Tools {
|
||||
if tool.Vendor == ToolVendor && tool.Name == ToolName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func LookupProperty(properties *[]cdx.Property, key string) string {
|
||||
for _, p := range lo.FromPtr(properties) {
|
||||
if p.Name == Namespace+key {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func UnmarshalProperties(properties *[]cdx.Property) map[string]string {
|
||||
props := map[string]string{}
|
||||
for _, prop := range lo.FromPtr(properties) {
|
||||
if !strings.HasPrefix(prop.Name, Namespace) {
|
||||
continue
|
||||
}
|
||||
props[strings.TrimPrefix(prop.Name, Namespace)] = prop.Value
|
||||
}
|
||||
return props
|
||||
}
|
||||
|
||||
func cdxAdvisories(refs []string) *[]cdx.Advisory {
|
||||
var advs []cdx.Advisory
|
||||
for _, ref := range refs {
|
||||
advs = append(advs, cdx.Advisory{
|
||||
URL: ref,
|
||||
})
|
||||
}
|
||||
return &advs
|
||||
}
|
||||
|
||||
func cwes(cweIDs []string) *[]int {
|
||||
// to skip cdx.Vulnerability.CWEs when generating json
|
||||
// we should return 'clear' nil without 'type' interface part
|
||||
if cweIDs == nil {
|
||||
return nil
|
||||
}
|
||||
var ret []int
|
||||
for _, cweID := range cweIDs {
|
||||
number, err := strconv.Atoi(strings.TrimPrefix(strings.ToLower(cweID), "cwe-"))
|
||||
if err != nil {
|
||||
log.Logger.Debugf("cwe id parse error: %s", err)
|
||||
continue
|
||||
}
|
||||
ret = append(ret, number)
|
||||
}
|
||||
return &ret
|
||||
}
|
||||
|
||||
func cdxRatings(vulnerability types.DetectedVulnerability) *[]cdx.VulnerabilityRating {
|
||||
rates := make([]cdx.VulnerabilityRating, 0) // To export an empty array in JSON
|
||||
for sourceID, severity := range vulnerability.VendorSeverity {
|
||||
// When the vendor also provides CVSS score/vector
|
||||
if cvss, ok := vulnerability.CVSS[sourceID]; ok {
|
||||
if cvss.V2Score != 0 || cvss.V2Vector != "" {
|
||||
rates = append(rates, cdxRatingV2(sourceID, severity, cvss))
|
||||
}
|
||||
if cvss.V3Score != 0 || cvss.V3Vector != "" {
|
||||
rates = append(rates, cdxRatingV3(sourceID, severity, cvss))
|
||||
}
|
||||
} else { // When the vendor provides only severity
|
||||
rate := cdx.VulnerabilityRating{
|
||||
Source: &cdx.Source{
|
||||
Name: string(sourceID),
|
||||
},
|
||||
Severity: toCDXSeverity(severity),
|
||||
}
|
||||
rates = append(rates, rate)
|
||||
}
|
||||
}
|
||||
|
||||
// For consistency
|
||||
sort.Slice(rates, func(i, j int) bool {
|
||||
if rates[i].Source.Name != rates[j].Source.Name {
|
||||
return rates[i].Source.Name < rates[j].Source.Name
|
||||
}
|
||||
if rates[i].Method != rates[j].Method {
|
||||
return rates[i].Method < rates[j].Method
|
||||
}
|
||||
if rates[i].Score != nil && rates[j].Score != nil {
|
||||
return *rates[i].Score < *rates[j].Score
|
||||
}
|
||||
return rates[i].Vector < rates[j].Vector
|
||||
})
|
||||
return &rates
|
||||
}
|
||||
|
||||
func cdxRatingV2(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
||||
cdxSeverity := toCDXSeverity(severity)
|
||||
|
||||
// Trivy keeps only CVSSv3 severity for NVD.
|
||||
// The CVSSv2 severity must be calculated according to CVSSv2 score.
|
||||
if sourceID == vulnerability.NVD {
|
||||
cdxSeverity = nvdSeverityV2(cvss.V2Score)
|
||||
}
|
||||
return cdx.VulnerabilityRating{
|
||||
Source: &cdx.Source{
|
||||
Name: string(sourceID),
|
||||
},
|
||||
Score: &cvss.V2Score,
|
||||
Method: cdx.ScoringMethodCVSSv2,
|
||||
Severity: cdxSeverity,
|
||||
Vector: cvss.V2Vector,
|
||||
}
|
||||
}
|
||||
|
||||
func cdxRatingV3(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
||||
rate := cdx.VulnerabilityRating{
|
||||
Source: &cdx.Source{
|
||||
Name: string(sourceID),
|
||||
},
|
||||
Score: &cvss.V3Score,
|
||||
Method: cdx.ScoringMethodCVSSv3,
|
||||
Severity: toCDXSeverity(severity),
|
||||
Vector: cvss.V3Vector,
|
||||
}
|
||||
if strings.HasPrefix(cvss.V3Vector, "CVSS:3.1") {
|
||||
rate.Method = cdx.ScoringMethodCVSSv31
|
||||
}
|
||||
return rate
|
||||
}
|
||||
|
||||
func nvdSeverityV2(score float64) cdx.Severity {
|
||||
// cf. https://nvd.nist.gov/vuln-metrics/cvss
|
||||
switch {
|
||||
case score < 4.0:
|
||||
return cdx.SeverityInfo
|
||||
case 4.0 <= score && score < 7.0:
|
||||
return cdx.SeverityMedium
|
||||
case 7.0 <= score:
|
||||
return cdx.SeverityHigh
|
||||
}
|
||||
return cdx.SeverityUnknown
|
||||
}
|
||||
|
||||
func toCDXSeverity(s dtypes.Severity) cdx.Severity {
|
||||
switch s {
|
||||
case dtypes.SeverityLow:
|
||||
return cdx.SeverityLow
|
||||
case dtypes.SeverityMedium:
|
||||
return cdx.SeverityMedium
|
||||
case dtypes.SeverityHigh:
|
||||
return cdx.SeverityHigh
|
||||
case dtypes.SeverityCritical:
|
||||
return cdx.SeverityCritical
|
||||
default:
|
||||
return cdx.SeverityUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func cdxSource(source *dtypes.DataSource) *cdx.Source {
|
||||
if source == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &cdx.Source{
|
||||
Name: string(source.ID),
|
||||
URL: source.URL,
|
||||
}
|
||||
}
|
||||
|
||||
func cdxAffects(ref, version string) cdx.Affects {
|
||||
return cdx.Affects{
|
||||
Ref: ref,
|
||||
Range: &[]cdx.AffectedVersions{
|
||||
{
|
||||
Version: version,
|
||||
Status: cdx.VulnerabilityStatusAffected,
|
||||
// "AffectedVersions.Range" is not included, because it does not exist in DetectedVulnerability.
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -2,32 +2,22 @@ package cyclonedx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||
"github.com/google/uuid"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
dtypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||
"github.com/aquasecurity/trivy/pkg/digest"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/purl"
|
||||
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
const (
|
||||
ToolVendor = "aquasecurity"
|
||||
ToolName = "trivy"
|
||||
Namespace = ToolVendor + ":" + ToolName + ":"
|
||||
|
||||
PropertySchemaVersion = "SchemaVersion"
|
||||
PropertyType = "Type"
|
||||
PropertyClass = "Class"
|
||||
@@ -50,9 +40,6 @@ const (
|
||||
PropertyFilePath = "FilePath"
|
||||
PropertyLayerDigest = "LayerDigest"
|
||||
PropertyLayerDiffID = "LayerDiffID"
|
||||
|
||||
// https://json-schema.org/understanding-json-schema/reference/string.html#dates-and-times
|
||||
timeLayout = "2006-01-02T15:04:05+00:00"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -60,223 +47,44 @@ var (
|
||||
)
|
||||
|
||||
type Marshaler struct {
|
||||
appVersion string // Trivy version
|
||||
clock clock.Clock
|
||||
newUUID newUUID
|
||||
core *core.CycloneDX
|
||||
}
|
||||
|
||||
type newUUID func() uuid.UUID
|
||||
|
||||
type marshalOption func(*Marshaler)
|
||||
|
||||
func WithClock(clock clock.Clock) marshalOption {
|
||||
return func(opts *Marshaler) {
|
||||
opts.clock = clock
|
||||
func NewMarshaler(version string, opts ...core.Option) *Marshaler {
|
||||
return &Marshaler{
|
||||
core: core.NewCycloneDX(version, opts...),
|
||||
}
|
||||
}
|
||||
|
||||
func WithNewUUID(newUUID newUUID) marshalOption {
|
||||
return func(opts *Marshaler) {
|
||||
opts.newUUID = newUUID
|
||||
}
|
||||
}
|
||||
|
||||
func NewMarshaler(version string, opts ...marshalOption) *Marshaler {
|
||||
e := &Marshaler{
|
||||
appVersion: version,
|
||||
clock: clock.RealClock{},
|
||||
newUUID: uuid.New,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(e)
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// Marshal converts the Trivy report to the CycloneDX format
|
||||
func (e *Marshaler) Marshal(report types.Report) (*cdx.BOM, error) {
|
||||
bom := cdx.NewBOM()
|
||||
bom.SerialNumber = e.newUUID().URN()
|
||||
metadataComponent, err := e.reportToCdxComponent(report)
|
||||
// Convert
|
||||
root, err := e.MarshalReport(report)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse metadata component: %w", err)
|
||||
return nil, xerrors.Errorf("failed to marshal report: %w", err)
|
||||
}
|
||||
|
||||
bom.Metadata = e.cdxMetadata()
|
||||
bom.Metadata.Component = metadataComponent
|
||||
|
||||
bom.Components, bom.Dependencies, bom.Vulnerabilities, err = e.marshalComponents(report, bom.Metadata.Component.BOMRef)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse components: %w", err)
|
||||
}
|
||||
|
||||
return bom, nil
|
||||
return e.core.Marshal(root), nil
|
||||
}
|
||||
|
||||
// MarshalVulnerabilities converts the Trivy report to the CycloneDX format only with vulnerabilities.
|
||||
// The output refers to another CycloneDX SBOM.
|
||||
func (e *Marshaler) MarshalVulnerabilities(report types.Report) (*cdx.BOM, error) {
|
||||
vulnMap := map[string]cdx.Vulnerability{}
|
||||
for _, result := range report.Results {
|
||||
for _, vuln := range result.Vulnerabilities {
|
||||
ref, err := externalRef(report.CycloneDX.SerialNumber, vuln.PkgRef)
|
||||
func (e *Marshaler) MarshalReport(r types.Report) (*core.Component, error) {
|
||||
// Metadata component
|
||||
root, err := e.rootComponent(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := vulnMap[vuln.VulnerabilityID]; ok {
|
||||
*v.Affects = append(*v.Affects, cdxAffects(ref, vuln.InstalledVersion))
|
||||
} else {
|
||||
vulnMap[vuln.VulnerabilityID] = toCdxVulnerability(ref, vuln)
|
||||
}
|
||||
}
|
||||
}
|
||||
vulns := maps.Values(vulnMap)
|
||||
sort.Slice(vulns, func(i, j int) bool {
|
||||
return vulns[i].ID > vulns[j].ID
|
||||
})
|
||||
|
||||
bom := cdx.NewBOM()
|
||||
bom.Metadata = e.cdxMetadata()
|
||||
|
||||
// Fill the detected vulnerabilities
|
||||
bom.Vulnerabilities = &vulns
|
||||
|
||||
// Use the original component as is
|
||||
bom.Metadata.Component = &cdx.Component{
|
||||
Name: report.CycloneDX.Metadata.Component.Name,
|
||||
Version: report.CycloneDX.Metadata.Component.Version,
|
||||
Type: cdx.ComponentType(report.CycloneDX.Metadata.Component.Type),
|
||||
}
|
||||
|
||||
// Overwrite the bom ref as it must be the BOM ref of the original CycloneDX.
|
||||
// e.g.
|
||||
// "metadata" : {
|
||||
// "timestamp" : "2022-07-02T00:00:00Z",
|
||||
// "component" : {
|
||||
// "name" : "Acme Product",
|
||||
// "version": "2.4.0",
|
||||
// "type" : "application",
|
||||
// "bom-ref" : "urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1"
|
||||
// }
|
||||
// },
|
||||
if report.CycloneDX.SerialNumber != "" { // bomRef is optional field - https://cyclonedx.org/docs/1.4/json/#metadata_component_bom-ref
|
||||
bom.Metadata.Component.BOMRef = fmt.Sprintf("%s/%d", report.CycloneDX.SerialNumber, report.CycloneDX.Version)
|
||||
}
|
||||
return bom, nil
|
||||
}
|
||||
|
||||
func (e *Marshaler) cdxMetadata() *cdx.Metadata {
|
||||
return &cdx.Metadata{
|
||||
Timestamp: e.clock.Now().UTC().Format(timeLayout),
|
||||
Tools: &[]cdx.Tool{
|
||||
{
|
||||
Vendor: ToolVendor,
|
||||
Name: ToolName,
|
||||
Version: e.appVersion,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func externalRef(bomLink string, bomRef string) (string, error) {
|
||||
// bomLink is optional field: https://cyclonedx.org/docs/1.4/json/#vulnerabilities_items_bom-ref
|
||||
if bomLink == "" {
|
||||
return bomRef, nil
|
||||
}
|
||||
if !strings.HasPrefix(bomLink, "urn:uuid:") {
|
||||
return "", xerrors.Errorf("%q: %w", bomLink, ErrInvalidBOMLink)
|
||||
}
|
||||
return fmt.Sprintf("%s/%d#%s", strings.Replace(bomLink, "uuid", "cdx", 1), cdx.BOMFileFormatJSON, bomRef), nil
|
||||
}
|
||||
|
||||
func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Component, *[]cdx.Dependency, *[]cdx.Vulnerability, error) {
|
||||
components := make([]cdx.Component, 0) // To export an empty array in JSON
|
||||
// we use map to avoid duplicate components
|
||||
dependencies := map[string]cdx.Dependency{}
|
||||
metadataDependencies := make([]string, 0) // To export an empty array in JSON
|
||||
libraryUniqMap := map[string]struct{}{}
|
||||
vulnMap := map[string]cdx.Vulnerability{}
|
||||
for _, result := range r.Results {
|
||||
bomRefMap := map[string]string{}
|
||||
pkgIDToRef := map[string]string{}
|
||||
var directDepRefs []string
|
||||
|
||||
// Get dependency parents first
|
||||
parents := ftypes.Packages(result.Packages).ParentDeps()
|
||||
|
||||
for _, pkg := range result.Packages {
|
||||
pkgComponent, err := pkgToCdxComponent(result.Type, r.Metadata, result.Class, pkg)
|
||||
components, err := e.marshalResult(r.Metadata, result)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("failed to parse pkg: %w", err)
|
||||
}
|
||||
pkgID := packageID(result.Target, pkg.Name, utils.FormatVersion(pkg), pkg.FilePath)
|
||||
bomRefMap[pkgID] = pkgComponent.BOMRef
|
||||
if pkg.ID != "" {
|
||||
pkgIDToRef[pkg.ID] = pkgComponent.BOMRef
|
||||
}
|
||||
// This package is a direct dependency
|
||||
if !pkg.Indirect || len(parents[pkg.ID]) == 0 {
|
||||
directDepRefs = append(directDepRefs, pkgComponent.BOMRef)
|
||||
}
|
||||
|
||||
// When multiple lock files have the same dependency with the same name and version,
|
||||
// "bom-ref" (PURL technically) of Library components may conflict.
|
||||
// In that case, only one Library component will be added and
|
||||
// some Application components will refer to the same component.
|
||||
// e.g.
|
||||
// Application component (/app1/package-lock.json)
|
||||
// |
|
||||
// | Application component (/app2/package-lock.json)
|
||||
// | |
|
||||
// └----┴----> Library component (npm package, express-4.17.3)
|
||||
//
|
||||
if _, ok := libraryUniqMap[pkgComponent.BOMRef]; !ok {
|
||||
libraryUniqMap[pkgComponent.BOMRef] = struct{}{}
|
||||
|
||||
// For components
|
||||
// ref. https://cyclonedx.org/use-cases/#inventory
|
||||
components = append(components, pkgComponent)
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate packages again to build dependency graph
|
||||
for _, pkg := range result.Packages {
|
||||
deps := lo.FilterMap(pkg.DependsOn, func(dep string, _ int) (string, bool) {
|
||||
if ref, ok := pkgIDToRef[dep]; ok {
|
||||
return ref, true
|
||||
}
|
||||
return "", false
|
||||
})
|
||||
if len(deps) == 0 {
|
||||
continue
|
||||
}
|
||||
sort.Strings(deps)
|
||||
ref := pkgIDToRef[pkg.ID]
|
||||
dependencies[ref] = cdx.Dependency{
|
||||
Ref: ref,
|
||||
Dependencies: &deps,
|
||||
}
|
||||
}
|
||||
sort.Strings(directDepRefs)
|
||||
|
||||
for _, vuln := range result.Vulnerabilities {
|
||||
// Take a bom-ref
|
||||
pkgID := packageID(result.Target, vuln.PkgName, vuln.InstalledVersion, vuln.PkgPath)
|
||||
ref := bomRefMap[pkgID]
|
||||
if v, ok := vulnMap[vuln.VulnerabilityID]; ok {
|
||||
// If a vulnerability depends on multiple packages,
|
||||
// it will be commonised into a single vulnerability.
|
||||
// Vulnerability component (CVE-2020-26247)
|
||||
// -> Library component (nokogiri /srv/app1/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
||||
// -> Library component (nokogiri /srv/app2/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
||||
*v.Affects = append(*v.Affects, cdxAffects(ref, vuln.InstalledVersion))
|
||||
} else {
|
||||
vulnMap[vuln.VulnerabilityID] = toCdxVulnerability(ref, vuln)
|
||||
return nil, err
|
||||
}
|
||||
root.Components = append(root.Components, components...)
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (e *Marshaler) marshalResult(metadata types.Metadata, result types.Result) ([]*core.Component, error) {
|
||||
if result.Type == ftypes.NodePkg || result.Type == ftypes.PythonPkg ||
|
||||
result.Type == ftypes.GemSpec || result.Type == ftypes.Jar || result.Type == ftypes.CondaPkg {
|
||||
// If a package is language-specific package that isn't associated with a lock file,
|
||||
@@ -289,7 +97,11 @@ func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Com
|
||||
// ref. https://cyclonedx.org/use-cases/#inventory
|
||||
|
||||
// Dependency graph from #1 to #2
|
||||
metadataDependencies = append(metadataDependencies, directDepRefs...)
|
||||
components, err := e.marshalPackages(metadata, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return components, nil
|
||||
} else if result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg {
|
||||
// If a package is OS package, it will be a dependency of "Operating System" component.
|
||||
// e.g.
|
||||
@@ -308,120 +120,149 @@ func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Com
|
||||
// -> Library component (npm package, lodash-4.17.21) --- #3
|
||||
// -> etc.
|
||||
|
||||
resultComponent := e.resultToCdxComponent(result, r.Metadata.OS)
|
||||
components = append(components, resultComponent)
|
||||
// #2
|
||||
appComponent := e.resultComponent(result, metadata.OS)
|
||||
|
||||
// #3
|
||||
components, err := e.marshalPackages(metadata, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Dependency graph from #2 to #3
|
||||
dependencies[resultComponent.BOMRef] = cdx.Dependency{
|
||||
Ref: resultComponent.BOMRef,
|
||||
Dependencies: &directDepRefs,
|
||||
}
|
||||
appComponent.Components = components
|
||||
|
||||
// Dependency graph from #1 to #2
|
||||
metadataDependencies = append(metadataDependencies, resultComponent.BOMRef)
|
||||
}
|
||||
return []*core.Component{appComponent}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
vulns := maps.Values(vulnMap)
|
||||
sort.Slice(vulns, func(i, j int) bool {
|
||||
return vulns[i].ID > vulns[j].ID
|
||||
func (e *Marshaler) marshalPackages(metadata types.Metadata, result types.Result) ([]*core.Component, error) {
|
||||
// Get dependency parents first
|
||||
parents := ftypes.Packages(result.Packages).ParentDeps()
|
||||
|
||||
// Group vulnerabilities by package ID
|
||||
vulns := lo.GroupBy(result.Vulnerabilities, func(v types.DetectedVulnerability) string {
|
||||
return lo.Ternary(v.PkgID == "", fmt.Sprintf("%s@%s", v.PkgName, v.InstalledVersion), v.PkgID)
|
||||
})
|
||||
|
||||
dependencies[bomRef] = cdx.Dependency{
|
||||
Ref: bomRef,
|
||||
Dependencies: &metadataDependencies,
|
||||
// Create package map
|
||||
pkgs := lo.SliceToMap(result.Packages, func(pkg ftypes.Package) (string, Package) {
|
||||
pkgID := lo.Ternary(pkg.ID == "", fmt.Sprintf("%s@%s", pkg.Name, utils.FormatVersion(pkg)), pkg.ID)
|
||||
return pkgID, Package{
|
||||
Type: result.Type,
|
||||
Metadata: metadata,
|
||||
Package: pkg,
|
||||
Vulnerabilities: vulns[pkgID],
|
||||
}
|
||||
dependencyList := maps.Values(dependencies)
|
||||
sort.Slice(dependencyList, func(i, j int) bool {
|
||||
return dependencyList[i].Ref < dependencyList[j].Ref
|
||||
})
|
||||
return &components, &dependencyList, &vulns, nil
|
||||
|
||||
var directComponents []*core.Component
|
||||
for _, pkg := range pkgs {
|
||||
// Skip indirect dependencies
|
||||
if pkg.Indirect && len(parents[pkg.ID]) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Recursive packages from direct dependencies
|
||||
if component, err := e.marshalPackage(pkg, pkgs, map[string]*core.Component{}); err != nil {
|
||||
return nil, nil
|
||||
} else if component != nil {
|
||||
directComponents = append(directComponents, component)
|
||||
}
|
||||
}
|
||||
|
||||
return directComponents, nil
|
||||
}
|
||||
|
||||
func packageID(target, pkgName, pkgVersion, pkgFilePath string) string {
|
||||
return fmt.Sprintf("%s/%s/%s/%s", target, pkgName, pkgVersion, pkgFilePath)
|
||||
type Package struct {
|
||||
ftypes.Package
|
||||
Type string
|
||||
Metadata types.Metadata
|
||||
Vulnerabilities []types.DetectedVulnerability
|
||||
}
|
||||
|
||||
func toCdxVulnerability(bomRef string, vuln types.DetectedVulnerability) cdx.Vulnerability {
|
||||
v := cdx.Vulnerability{
|
||||
ID: vuln.VulnerabilityID,
|
||||
Source: cdxSource(vuln.DataSource),
|
||||
Ratings: cdxRatings(vuln),
|
||||
CWEs: cwes(vuln.CweIDs),
|
||||
Description: vuln.Description,
|
||||
Advisories: cdxAdvisories(vuln.References),
|
||||
}
|
||||
if vuln.FixedVersion != "" {
|
||||
v.Recommendation = fmt.Sprintf("Upgrade %s to version %s", vuln.PkgName, vuln.FixedVersion)
|
||||
}
|
||||
if vuln.PublishedDate != nil {
|
||||
v.Published = vuln.PublishedDate.Format(timeLayout)
|
||||
}
|
||||
if vuln.LastModifiedDate != nil {
|
||||
v.Updated = vuln.LastModifiedDate.Format(timeLayout)
|
||||
func (e *Marshaler) marshalPackage(pkg Package, pkgs map[string]Package, components map[string]*core.Component,
|
||||
) (*core.Component, error) {
|
||||
if c, ok := components[pkg.ID]; ok {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
v.Affects = &[]cdx.Affects{cdxAffects(bomRef, vuln.InstalledVersion)}
|
||||
component, err := pkgComponent(pkg)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse pkg: %w", err)
|
||||
}
|
||||
components[pkg.ID] = component
|
||||
|
||||
return v
|
||||
// Iterate dependencies
|
||||
for _, dep := range pkg.DependsOn {
|
||||
childPkg, ok := pkgs[dep]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
child, err := e.marshalPackage(childPkg, pkgs, components)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse pkg: %w", err)
|
||||
}
|
||||
component.Components = append(component.Components, child)
|
||||
}
|
||||
return component, nil
|
||||
}
|
||||
|
||||
func (e *Marshaler) reportToCdxComponent(r types.Report) (*cdx.Component, error) {
|
||||
component := &cdx.Component{
|
||||
func (e *Marshaler) rootComponent(r types.Report) (*core.Component, error) {
|
||||
root := &core.Component{
|
||||
Name: r.ArtifactName,
|
||||
}
|
||||
|
||||
properties := []cdx.Property{
|
||||
cdxProperty(PropertySchemaVersion, strconv.Itoa(r.SchemaVersion)),
|
||||
}
|
||||
|
||||
if r.Metadata.Size != 0 {
|
||||
properties = appendProperties(properties, PropertySize, strconv.FormatInt(r.Metadata.Size, 10))
|
||||
props := map[string]string{
|
||||
PropertySchemaVersion: strconv.Itoa(r.SchemaVersion),
|
||||
}
|
||||
|
||||
switch r.ArtifactType {
|
||||
case ftypes.ArtifactContainerImage:
|
||||
component.Type = cdx.ComponentTypeContainer
|
||||
root.Type = cdx.ComponentTypeContainer
|
||||
props[PropertyImageID] = r.Metadata.ImageID
|
||||
|
||||
p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to new package url for oci: %w", err)
|
||||
} else if p.Type != "" {
|
||||
root.PackageURL = &p
|
||||
}
|
||||
properties = appendProperties(properties, PropertyImageID, r.Metadata.ImageID)
|
||||
|
||||
if p.Type == "" {
|
||||
component.BOMRef = e.newUUID().String()
|
||||
} else {
|
||||
component.BOMRef = p.ToString()
|
||||
component.PackageURL = p.ToString()
|
||||
}
|
||||
case ftypes.ArtifactVM:
|
||||
component.Type = cdx.ComponentTypeContainer
|
||||
component.BOMRef = e.newUUID().String()
|
||||
root.Type = cdx.ComponentTypeContainer
|
||||
case ftypes.ArtifactFilesystem, ftypes.ArtifactRemoteRepository:
|
||||
component.Type = cdx.ComponentTypeApplication
|
||||
component.BOMRef = e.newUUID().String()
|
||||
root.Type = cdx.ComponentTypeApplication
|
||||
}
|
||||
|
||||
for _, d := range r.Metadata.RepoDigests {
|
||||
properties = appendProperties(properties, PropertyRepoDigest, d)
|
||||
}
|
||||
for _, d := range r.Metadata.DiffIDs {
|
||||
properties = appendProperties(properties, PropertyDiffID, d)
|
||||
}
|
||||
for _, t := range r.Metadata.RepoTags {
|
||||
properties = appendProperties(properties, PropertyRepoTag, t)
|
||||
if r.Metadata.Size != 0 {
|
||||
props[PropertySize] = strconv.FormatInt(r.Metadata.Size, 10)
|
||||
}
|
||||
|
||||
component.Properties = &properties
|
||||
if len(r.Metadata.RepoDigests) > 0 {
|
||||
props[PropertyRepoDigest] = strings.Join(r.Metadata.RepoDigests, ",")
|
||||
}
|
||||
if len(r.Metadata.DiffIDs) > 0 {
|
||||
props[PropertyDiffID] = strings.Join(r.Metadata.DiffIDs, ",")
|
||||
}
|
||||
if len(r.Metadata.RepoTags) > 0 {
|
||||
props[PropertyRepoTag] = strings.Join(r.Metadata.RepoTags, ",")
|
||||
}
|
||||
|
||||
return component, nil
|
||||
root.Properties = filterProperties(props)
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx.Component {
|
||||
component := cdx.Component{
|
||||
func (e *Marshaler) resultComponent(r types.Result, osFound *ftypes.OS) *core.Component {
|
||||
component := &core.Component{
|
||||
Name: r.Target,
|
||||
Properties: &[]cdx.Property{
|
||||
cdxProperty(PropertyType, r.Type),
|
||||
cdxProperty(PropertyClass, string(r.Class)),
|
||||
Properties: map[string]string{
|
||||
PropertyType: r.Type,
|
||||
PropertyClass: string(r.Class),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -429,7 +270,6 @@ func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx
|
||||
case types.ClassOSPkg:
|
||||
// UUID needs to be generated since Operating System Component cannot generate PURL.
|
||||
// https://cyclonedx.org/use-cases/#known-vulnerabilities
|
||||
component.BOMRef = e.newUUID().String()
|
||||
if osFound != nil {
|
||||
component.Name = osFound.Family
|
||||
component.Version = osFound.Name
|
||||
@@ -438,296 +278,46 @@ func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx
|
||||
case types.ClassLangPkg:
|
||||
// UUID needs to be generated since Application Component cannot generate PURL.
|
||||
// https://cyclonedx.org/use-cases/#known-vulnerabilities
|
||||
component.BOMRef = e.newUUID().String()
|
||||
component.Type = cdx.ComponentTypeApplication
|
||||
case types.ClassConfig:
|
||||
// TODO: Config support
|
||||
component.BOMRef = e.newUUID().String()
|
||||
component.Type = cdx.ComponentTypeFile
|
||||
}
|
||||
|
||||
return component
|
||||
}
|
||||
|
||||
func pkgToCdxComponent(pkgType string, meta types.Metadata, class types.ResultClass, pkg ftypes.Package) (cdx.Component, error) {
|
||||
pu, err := purl.NewPackageURL(pkgType, meta, pkg)
|
||||
func pkgComponent(pkg Package) (*core.Component, error) {
|
||||
pu, err := purl.NewPackageURL(pkg.Type, pkg.Metadata, pkg.Package)
|
||||
if err != nil {
|
||||
return cdx.Component{}, xerrors.Errorf("failed to new package purl: %w", err)
|
||||
}
|
||||
properties := cdxProperties(pkgType, pkg)
|
||||
var hashes *[]cdx.Hash
|
||||
if pkg.Digest != "" && class == types.ClassOSPkg {
|
||||
if alg := cdxHashAlgorithm(pkg.Digest.Algorithm()); alg != "" {
|
||||
hashes = &[]cdx.Hash{
|
||||
{
|
||||
Algorithm: alg,
|
||||
Value: pkg.Digest.Encoded(),
|
||||
},
|
||||
}
|
||||
return nil, xerrors.Errorf("failed to new package purl: %w", err)
|
||||
}
|
||||
|
||||
properties := map[string]string{
|
||||
PropertyPkgID: pkg.ID,
|
||||
PropertyPkgType: pkg.Type,
|
||||
PropertyFilePath: pkg.FilePath,
|
||||
PropertySrcName: pkg.SrcName,
|
||||
PropertySrcVersion: pkg.SrcVersion,
|
||||
PropertySrcRelease: pkg.SrcRelease,
|
||||
PropertySrcEpoch: strconv.Itoa(pkg.SrcEpoch),
|
||||
PropertyModularitylabel: pkg.Modularitylabel,
|
||||
PropertyLayerDigest: pkg.Layer.Digest,
|
||||
PropertyLayerDiffID: pkg.Layer.DiffID,
|
||||
}
|
||||
component := cdx.Component{
|
||||
|
||||
return &core.Component{
|
||||
Type: cdx.ComponentTypeLibrary,
|
||||
Name: pkg.Name,
|
||||
Version: pu.Version,
|
||||
BOMRef: pu.BOMRef(),
|
||||
PackageURL: pu.ToString(),
|
||||
Properties: properties,
|
||||
Hashes: hashes,
|
||||
}
|
||||
PackageURL: &pu,
|
||||
Supplier: pkg.Maintainer,
|
||||
Licenses: pkg.Licenses,
|
||||
Hashes: lo.Ternary(pkg.Digest == "", nil, []digest.Digest{pkg.Digest}),
|
||||
Properties: filterProperties(properties),
|
||||
Vulnerabilities: pkg.Vulnerabilities,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if len(pkg.Licenses) != 0 {
|
||||
choices := lo.Map(pkg.Licenses, func(license string, i int) cdx.LicenseChoice {
|
||||
return cdx.LicenseChoice{Expression: license}
|
||||
func filterProperties(props map[string]string) map[string]string {
|
||||
return lo.OmitBy(props, func(key string, value string) bool {
|
||||
return value == "" || (key == PropertySrcEpoch && value == "0")
|
||||
})
|
||||
component.Licenses = lo.ToPtr(cdx.Licenses(choices))
|
||||
}
|
||||
|
||||
if pkg.Maintainer != "" {
|
||||
component.Supplier = &cdx.OrganizationalEntity{
|
||||
Name: pkg.Maintainer,
|
||||
}
|
||||
}
|
||||
|
||||
return component, nil
|
||||
}
|
||||
|
||||
func cdxProperties(pkgType string, pkg ftypes.Package) *[]cdx.Property {
|
||||
props := []struct {
|
||||
name string
|
||||
value string
|
||||
}{
|
||||
{
|
||||
PropertyPkgID,
|
||||
pkg.ID,
|
||||
},
|
||||
{
|
||||
PropertyPkgType,
|
||||
pkgType,
|
||||
},
|
||||
{
|
||||
PropertyFilePath,
|
||||
pkg.FilePath,
|
||||
},
|
||||
{
|
||||
PropertySrcName,
|
||||
pkg.SrcName,
|
||||
},
|
||||
{
|
||||
PropertySrcVersion,
|
||||
pkg.SrcVersion,
|
||||
},
|
||||
{
|
||||
PropertySrcRelease,
|
||||
pkg.SrcRelease,
|
||||
},
|
||||
{
|
||||
PropertySrcEpoch,
|
||||
strconv.Itoa(pkg.SrcEpoch),
|
||||
},
|
||||
{
|
||||
PropertyModularitylabel,
|
||||
pkg.Modularitylabel,
|
||||
},
|
||||
{
|
||||
PropertyLayerDigest,
|
||||
pkg.Layer.Digest,
|
||||
},
|
||||
{
|
||||
PropertyLayerDiffID,
|
||||
pkg.Layer.DiffID,
|
||||
},
|
||||
}
|
||||
|
||||
var properties []cdx.Property
|
||||
for _, prop := range props {
|
||||
properties = appendProperties(properties, prop.name, prop.value)
|
||||
}
|
||||
if len(properties) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &properties
|
||||
}
|
||||
|
||||
func appendProperties(properties []cdx.Property, key, value string) []cdx.Property {
|
||||
if value == "" || (key == PropertySrcEpoch && value == "0") {
|
||||
return properties
|
||||
}
|
||||
return append(properties, cdxProperty(key, value))
|
||||
}
|
||||
|
||||
func cdxProperty(key, value string) cdx.Property {
|
||||
return cdx.Property{
|
||||
Name: Namespace + key,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func cdxAdvisories(refs []string) *[]cdx.Advisory {
|
||||
var advs []cdx.Advisory
|
||||
for _, ref := range refs {
|
||||
advs = append(advs, cdx.Advisory{
|
||||
URL: ref,
|
||||
})
|
||||
}
|
||||
return &advs
|
||||
}
|
||||
|
||||
func cwes(cweIDs []string) *[]int {
|
||||
// to skip cdx.Vulnerability.CWEs when generating json
|
||||
// we should return 'clear' nil without 'type' interface part
|
||||
if cweIDs == nil {
|
||||
return nil
|
||||
}
|
||||
var ret []int
|
||||
for _, cweID := range cweIDs {
|
||||
number, err := strconv.Atoi(strings.TrimPrefix(strings.ToLower(cweID), "cwe-"))
|
||||
if err != nil {
|
||||
log.Logger.Debugf("cwe id parse error: %s", err)
|
||||
continue
|
||||
}
|
||||
ret = append(ret, number)
|
||||
}
|
||||
return &ret
|
||||
}
|
||||
|
||||
func cdxRatings(vulnerability types.DetectedVulnerability) *[]cdx.VulnerabilityRating {
|
||||
rates := make([]cdx.VulnerabilityRating, 0) // To export an empty array in JSON
|
||||
for sourceID, severity := range vulnerability.VendorSeverity {
|
||||
// When the vendor also provides CVSS score/vector
|
||||
if cvss, ok := vulnerability.CVSS[sourceID]; ok {
|
||||
if cvss.V2Score != 0 || cvss.V2Vector != "" {
|
||||
rates = append(rates, cdxRatingV2(sourceID, severity, cvss))
|
||||
}
|
||||
if cvss.V3Score != 0 || cvss.V3Vector != "" {
|
||||
rates = append(rates, cdxRatingV3(sourceID, severity, cvss))
|
||||
}
|
||||
} else { // When the vendor provides only severity
|
||||
rate := cdx.VulnerabilityRating{
|
||||
Source: &cdx.Source{
|
||||
Name: string(sourceID),
|
||||
},
|
||||
Severity: toCDXSeverity(severity),
|
||||
}
|
||||
rates = append(rates, rate)
|
||||
}
|
||||
}
|
||||
|
||||
// For consistency
|
||||
sort.Slice(rates, func(i, j int) bool {
|
||||
if rates[i].Source.Name != rates[j].Source.Name {
|
||||
return rates[i].Source.Name < rates[j].Source.Name
|
||||
}
|
||||
if rates[i].Method != rates[j].Method {
|
||||
return rates[i].Method < rates[j].Method
|
||||
}
|
||||
if rates[i].Score != nil && rates[j].Score != nil {
|
||||
return *rates[i].Score < *rates[j].Score
|
||||
}
|
||||
return rates[i].Vector < rates[j].Vector
|
||||
})
|
||||
return &rates
|
||||
}
|
||||
|
||||
func cdxRatingV2(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
||||
cdxSeverity := toCDXSeverity(severity)
|
||||
|
||||
// Trivy keeps only CVSSv3 severity for NVD.
|
||||
// The CVSSv2 severity must be calculated according to CVSSv2 score.
|
||||
if sourceID == vulnerability.NVD {
|
||||
cdxSeverity = nvdSeverityV2(cvss.V2Score)
|
||||
}
|
||||
return cdx.VulnerabilityRating{
|
||||
Source: &cdx.Source{
|
||||
Name: string(sourceID),
|
||||
},
|
||||
Score: &cvss.V2Score,
|
||||
Method: cdx.ScoringMethodCVSSv2,
|
||||
Severity: cdxSeverity,
|
||||
Vector: cvss.V2Vector,
|
||||
}
|
||||
}
|
||||
|
||||
func nvdSeverityV2(score float64) cdx.Severity {
|
||||
// cf. https://nvd.nist.gov/vuln-metrics/cvss
|
||||
switch {
|
||||
case score < 4.0:
|
||||
return cdx.SeverityInfo
|
||||
case 4.0 <= score && score < 7.0:
|
||||
return cdx.SeverityMedium
|
||||
case 7.0 <= score:
|
||||
return cdx.SeverityHigh
|
||||
}
|
||||
return cdx.SeverityUnknown
|
||||
}
|
||||
|
||||
func cdxRatingV3(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
||||
rate := cdx.VulnerabilityRating{
|
||||
Source: &cdx.Source{
|
||||
Name: string(sourceID),
|
||||
},
|
||||
Score: &cvss.V3Score,
|
||||
Method: cdx.ScoringMethodCVSSv3,
|
||||
Severity: toCDXSeverity(severity),
|
||||
Vector: cvss.V3Vector,
|
||||
}
|
||||
if strings.HasPrefix(cvss.V3Vector, "CVSS:3.1") {
|
||||
rate.Method = cdx.ScoringMethodCVSSv31
|
||||
}
|
||||
return rate
|
||||
}
|
||||
|
||||
func toCDXSeverity(s dtypes.Severity) cdx.Severity {
|
||||
switch s {
|
||||
case dtypes.SeverityLow:
|
||||
return cdx.SeverityLow
|
||||
case dtypes.SeverityMedium:
|
||||
return cdx.SeverityMedium
|
||||
case dtypes.SeverityHigh:
|
||||
return cdx.SeverityHigh
|
||||
case dtypes.SeverityCritical:
|
||||
return cdx.SeverityCritical
|
||||
default:
|
||||
return cdx.SeverityUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func cdxSource(source *dtypes.DataSource) *cdx.Source {
|
||||
if source == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &cdx.Source{
|
||||
Name: string(source.ID),
|
||||
URL: source.URL,
|
||||
}
|
||||
}
|
||||
|
||||
func cdxAffects(ref, version string) cdx.Affects {
|
||||
return cdx.Affects{
|
||||
Ref: ref,
|
||||
Range: &[]cdx.AffectedVersions{
|
||||
{
|
||||
Version: version,
|
||||
Status: cdx.VulnerabilityStatusAffected,
|
||||
// "AffectedVersions.Range" is not included, because it does not exist in DetectedVulnerability.
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func cdxHashAlgorithm(algorithm digest.Algorithm) cdx.HashAlgorithm {
|
||||
switch algorithm {
|
||||
case digest.SHA1:
|
||||
return cdx.HashAlgoSHA1
|
||||
case digest.SHA256:
|
||||
return cdx.HashAlgoSHA256
|
||||
case digest.MD5:
|
||||
return cdx.HashAlgoMD5
|
||||
default:
|
||||
log.Logger.Debugf("Unable to convert %q algorithm to CycloneDX format", algorithm)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,8 @@ import (
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
|
||||
|
||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||
"github.com/samber/lo"
|
||||
@@ -23,7 +24,7 @@ var (
|
||||
ErrPURLEmpty = errors.New("purl empty error")
|
||||
)
|
||||
|
||||
type CycloneDX struct {
|
||||
type BOM struct {
|
||||
*types.SBOM
|
||||
|
||||
dependencies map[string][]string
|
||||
@@ -39,7 +40,7 @@ func DecodeJSON(r io.Reader) (*cdx.BOM, error) {
|
||||
return bom, nil
|
||||
}
|
||||
|
||||
func (c *CycloneDX) UnmarshalJSON(b []byte) error {
|
||||
func (c *BOM) UnmarshalJSON(b []byte) error {
|
||||
log.Logger.Debug("Unmarshaling CycloneDX JSON...")
|
||||
if c.SBOM == nil {
|
||||
c.SBOM = &types.SBOM{}
|
||||
@@ -49,7 +50,7 @@ func (c *CycloneDX) UnmarshalJSON(b []byte) error {
|
||||
return xerrors.Errorf("CycloneDX decode error: %w", err)
|
||||
}
|
||||
|
||||
if !isTrivySBOM(bom) {
|
||||
if !core.IsTrivySBOM(bom) {
|
||||
log.Logger.Warnf("Third-party SBOM may lead to inaccurate vulnerability detection")
|
||||
log.Logger.Warnf("Recommend using Trivy to generate SBOMs")
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func (c *CycloneDX) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CycloneDX) parseSBOM(bom *cdx.BOM) error {
|
||||
func (c *BOM) parseSBOM(bom *cdx.BOM) error {
|
||||
c.dependencies = dependencyMap(bom.Dependencies)
|
||||
c.components = componentMap(bom.Metadata, bom.Components)
|
||||
var seen = make(map[string]struct{})
|
||||
@@ -106,7 +107,7 @@ func (c *CycloneDX) parseSBOM(bom *cdx.BOM) error {
|
||||
}
|
||||
c.Packages = append(c.Packages, pkgInfo)
|
||||
case cdx.ComponentTypeApplication: // It would be a lock file in a CycloneDX report generated by Trivy
|
||||
if lookupProperty(component.Properties, PropertyType) == "" {
|
||||
if core.LookupProperty(component.Properties, PropertyType) == "" {
|
||||
continue
|
||||
}
|
||||
app, err := c.parseLangPkgs(component, seen)
|
||||
@@ -160,7 +161,7 @@ func (c *CycloneDX) parseSBOM(bom *cdx.BOM) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CycloneDX) parseOSPkgs(component cdx.Component, seen map[string]struct{}) (ftypes.PackageInfo, error) {
|
||||
func (c *BOM) parseOSPkgs(component cdx.Component, seen map[string]struct{}) (ftypes.PackageInfo, error) {
|
||||
components := c.walkDependencies(component.BOMRef, map[string]struct{}{})
|
||||
pkgs, err := parsePkgs(components, seen)
|
||||
if err != nil {
|
||||
@@ -172,7 +173,7 @@ func (c *CycloneDX) parseOSPkgs(component cdx.Component, seen map[string]struct{
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CycloneDX) parseLangPkgs(component cdx.Component, seen map[string]struct{}) (*ftypes.Application, error) {
|
||||
func (c *BOM) parseLangPkgs(component cdx.Component, seen map[string]struct{}) (*ftypes.Application, error) {
|
||||
components := c.walkDependencies(component.BOMRef, map[string]struct{}{})
|
||||
components = lo.UniqBy(components, func(c cdx.Component) string {
|
||||
return c.BOMRef
|
||||
@@ -205,7 +206,7 @@ func parsePkgs(components []cdx.Component, seen map[string]struct{}) ([]ftypes.P
|
||||
}
|
||||
|
||||
// walkDependencies takes all nested dependencies of the root component.
|
||||
func (c *CycloneDX) walkDependencies(rootRef string, uniqComponents map[string]struct{}) []cdx.Component {
|
||||
func (c *BOM) walkDependencies(rootRef string, uniqComponents map[string]struct{}) []cdx.Component {
|
||||
// e.g. Library A, B, C, D and E will be returned as dependencies of Application 1.
|
||||
// type: Application 1
|
||||
// - type: Library A
|
||||
@@ -325,7 +326,7 @@ func toOS(component cdx.Component) ftypes.OS {
|
||||
|
||||
func toApplication(component cdx.Component) *ftypes.Application {
|
||||
return &ftypes.Application{
|
||||
Type: lookupProperty(component.Properties, PropertyType),
|
||||
Type: core.LookupProperty(component.Properties, PropertyType),
|
||||
FilePath: component.Name,
|
||||
}
|
||||
}
|
||||
@@ -350,27 +351,25 @@ func toPackage(component cdx.Component) (bool, string, *ftypes.Package, error) {
|
||||
pkg.Licenses = append(pkg.Licenses, license.Expression)
|
||||
}
|
||||
|
||||
for _, prop := range lo.FromPtr(component.Properties) {
|
||||
if strings.HasPrefix(prop.Name, Namespace) {
|
||||
switch strings.TrimPrefix(prop.Name, Namespace) {
|
||||
for key, value := range core.UnmarshalProperties(component.Properties) {
|
||||
switch key {
|
||||
case PropertyPkgID:
|
||||
pkg.ID = prop.Value
|
||||
pkg.ID = value
|
||||
case PropertySrcName:
|
||||
pkg.SrcName = prop.Value
|
||||
pkg.SrcName = value
|
||||
case PropertySrcVersion:
|
||||
pkg.SrcVersion = prop.Value
|
||||
pkg.SrcVersion = value
|
||||
case PropertySrcRelease:
|
||||
pkg.SrcRelease = prop.Value
|
||||
pkg.SrcRelease = value
|
||||
case PropertySrcEpoch:
|
||||
pkg.SrcEpoch, err = strconv.Atoi(prop.Value)
|
||||
pkg.SrcEpoch, err = strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return false, "", nil, xerrors.Errorf("failed to parse source epoch: %w", err)
|
||||
}
|
||||
case PropertyModularitylabel:
|
||||
pkg.Modularitylabel = prop.Value
|
||||
pkg.Modularitylabel = value
|
||||
case PropertyLayerDiffID:
|
||||
pkg.Layer.DiffID = prop.Value
|
||||
}
|
||||
pkg.Layer.DiffID = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,25 +403,3 @@ func toTrivyCdxComponent(component cdx.Component) ftypes.Component {
|
||||
PackageURL: component.PackageURL,
|
||||
}
|
||||
}
|
||||
|
||||
func lookupProperty(properties *[]cdx.Property, key string) string {
|
||||
for _, p := range lo.FromPtr(properties) {
|
||||
if p.Name == Namespace+key {
|
||||
return p.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isTrivySBOM(c *cdx.BOM) bool {
|
||||
if c == nil || c.Metadata == nil || c.Metadata.Tools == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, tool := range *c.Metadata.Tools {
|
||||
if tool.Vendor == ToolVendor && tool.Name == ToolName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
var cdx cyclonedx.CycloneDX
|
||||
var cdx cyclonedx.BOM
|
||||
err = json.NewDecoder(f).Decode(&cdx)
|
||||
if tt.wantErr != "" {
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -187,14 +187,14 @@ func Decode(f io.Reader, format Format) (types.SBOM, error) {
|
||||
|
||||
switch format {
|
||||
case FormatCycloneDXJSON:
|
||||
v = &cyclonedx.CycloneDX{SBOM: &bom}
|
||||
v = &cyclonedx.BOM{SBOM: &bom}
|
||||
decoder = json.NewDecoder(f)
|
||||
case FormatAttestCycloneDXJSON:
|
||||
// dsse envelope
|
||||
// => in-toto attestation
|
||||
// => CycloneDX JSON
|
||||
v = &attestation.Statement{
|
||||
Predicate: &cyclonedx.CycloneDX{SBOM: &bom},
|
||||
Predicate: &cyclonedx.BOM{SBOM: &bom},
|
||||
}
|
||||
decoder = json.NewDecoder(f)
|
||||
case FormatLegacyCosignAttestCycloneDXJSON:
|
||||
@@ -204,7 +204,7 @@ func Decode(f io.Reader, format Format) (types.SBOM, error) {
|
||||
// => CycloneDX JSON
|
||||
v = &attestation.Statement{
|
||||
Predicate: &attestation.CosignPredicate{
|
||||
Data: &cyclonedx.CycloneDX{SBOM: &bom},
|
||||
Data: &cyclonedx.BOM{SBOM: &bom},
|
||||
},
|
||||
}
|
||||
decoder = json.NewDecoder(f)
|
||||
|
||||
Reference in New Issue
Block a user