From 18aa975ae25663d482a89700309e0239a906da72 Mon Sep 17 00:00:00 2001
From: Andrei Aaron <aaaron@luxoft.com>
Date: Wed, 13 Dec 2023 19:16:31 +0200
Subject: [PATCH] feat(CVE): add CVE severity counters to returned images and
 CVE list calls (#2131)

For CLI output is similar to:

CRITICAL 0, HIGH 1, MEDIUM 1, LOW 0, UNKNOWN 0, TOTAL 2

ID                SEVERITY  TITLE
CVE-2023-0464     HIGH      openssl: Denial of service by excessive resou...
CVE-2023-0465     MEDIUM    openssl: Invalid certificate policies in leaf...

Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
---
 pkg/cli/client/cve_cmd_internal_test.go       |  14 +-
 pkg/cli/client/cve_cmd_test.go                |   6 +-
 pkg/cli/client/image_cmd_internal_test.go     |  29 +-
 pkg/cli/client/image_cmd_test.go              |  39 +-
 pkg/cli/client/search_functions.go            |   8 +
 .../client/search_functions_internal_test.go  |  10 +
 pkg/cli/client/service.go                     |  11 +-
 pkg/common/model.go                           |   9 +-
 .../search/convert/convert_internal_test.go   |  69 +++-
 pkg/extensions/search/convert/cve.go          |  28 +-
 pkg/extensions/search/cve/cve.go              |  93 +++--
 pkg/extensions/search/cve/cve_test.go         | 246 +++++++++++-
 pkg/extensions/search/cve/model/models.go     |   9 +-
 pkg/extensions/search/cve/pagination_test.go  | 125 +++++-
 .../search/gql_generated/generated.go         | 373 +++++++++++++++++-
 .../search/gql_generated/models_gen.go        |  12 +
 pkg/extensions/search/resolver.go             |  12 +-
 pkg/extensions/search/schema.graphql          |  25 ++
 pkg/extensions/search/search_test.go          |  97 +++--
 pkg/test/mocks/cve_mock.go                    |   5 +-
 20 files changed, 1081 insertions(+), 139 deletions(-)

diff --git a/pkg/cli/client/cve_cmd_internal_test.go b/pkg/cli/client/cve_cmd_internal_test.go
index 5728cbd9d..0a59f9ac6 100644
--- a/pkg/cli/client/cve_cmd_internal_test.go
+++ b/pkg/cli/client/cve_cmd_internal_test.go
@@ -141,7 +141,8 @@ func TestSearchCVECmd(t *testing.T) {
 		err := cmd.Execute()
 		space := regexp.MustCompile(`\s+`)
 		str := space.ReplaceAllString(buff.String(), " ")
-		So(strings.TrimSpace(str), ShouldEqual, "ID SEVERITY TITLE dummyCVEID HIGH Title of that CVE")
+		So(strings.TrimSpace(str), ShouldEqual, "CRITICAL 0, HIGH 1, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 1 "+
+			"ID SEVERITY TITLE dummyCVEID HIGH Title of that CVE")
 		So(err, ShouldBeNil)
 	})
 
@@ -207,7 +208,8 @@ func TestSearchCVECmd(t *testing.T) {
 		err := cveCmd.Execute()
 		space := regexp.MustCompile(`\s+`)
 		str := space.ReplaceAllString(buff.String(), " ")
-		So(strings.TrimSpace(str), ShouldEqual, "ID SEVERITY TITLE dummyCVEID HIGH Title of that CVE")
+		So(strings.TrimSpace(str), ShouldEqual, "CRITICAL 0, HIGH 1, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 1 "+
+			"ID SEVERITY TITLE dummyCVEID HIGH Title of that CVE")
 		So(err, ShouldBeNil)
 	})
 
@@ -225,7 +227,9 @@ func TestSearchCVECmd(t *testing.T) {
 		So(buff.String(), ShouldEqual, `{"Tag":"dummyImageName:tag","CVEList":`+
 			`[{"Id":"dummyCVEID","Severity":"HIGH","Title":"Title of that CVE",`+
 			`"Description":"Description of the CVE","PackageList":[{"Name":"packagename",`+
-			`"InstalledVersion":"installedver","FixedVersion":"fixedver"}]}]}`+"\n")
+			`"InstalledVersion":"installedver","FixedVersion":"fixedver"}]}],"Summary":`+
+			`{"maxSeverity":"HIGH","unknownCount":0,"lowCount":0,"mediumCount":0,"highCount":1,`+
+			`"criticalCount":0,"count":1}}`+"\n")
 		So(err, ShouldBeNil)
 	})
 
@@ -243,7 +247,8 @@ func TestSearchCVECmd(t *testing.T) {
 		str := space.ReplaceAllString(buff.String(), " ")
 		So(strings.TrimSpace(str), ShouldEqual, `--- tag: dummyImageName:tag cvelist: - id: dummyCVEID`+
 			` severity: HIGH title: Title of that CVE description: Description of the CVE packagelist: `+
-			`- name: packagename installedversion: installedver fixedversion: fixedver`)
+			`- name: packagename installedversion: installedver fixedversion: fixedver `+
+			`summary: maxseverity: HIGH unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 1 criticalcount: 0 count: 1`)
 		So(err, ShouldBeNil)
 	})
 	Convey("Test CVE by image name - invalid format", t, func() {
@@ -508,6 +513,7 @@ func TestCVECommandGQL(t *testing.T) {
 			space := regexp.MustCompile(`\s+`)
 			str := space.ReplaceAllString(buff.String(), " ")
 			actual := strings.TrimSpace(str)
+			So(actual, ShouldContainSubstring, "CRITICAL 0, HIGH 1, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 1")
 			So(actual, ShouldContainSubstring, "dummyCVEID HIGH Title of that CVE")
 		})
 
diff --git a/pkg/cli/client/cve_cmd_test.go b/pkg/cli/client/cve_cmd_test.go
index d0876b28b..4175a92ae 100644
--- a/pkg/cli/client/cve_cmd_test.go
+++ b/pkg/cli/client/cve_cmd_test.go
@@ -634,7 +634,7 @@ func TestCVESort(t *testing.T) {
 		str := space.ReplaceAllString(buff.String(), " ")
 		actual := strings.TrimSpace(str)
 		So(actual, ShouldResemble,
-			"ID SEVERITY TITLE "+
+			"CRITICAL 1, HIGH 1, MEDIUM 2, LOW 1, UNKNOWN 0, TOTAL 5 ID SEVERITY TITLE "+
 				"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
 				"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
 				"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
@@ -652,7 +652,7 @@ func TestCVESort(t *testing.T) {
 		str = space.ReplaceAllString(buff.String(), " ")
 		actual = strings.TrimSpace(str)
 		So(actual, ShouldResemble,
-			"ID SEVERITY TITLE "+
+			"CRITICAL 1, HIGH 1, MEDIUM 2, LOW 1, UNKNOWN 0, TOTAL 5 ID SEVERITY TITLE "+
 				"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat... "+
 				"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
 				"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
@@ -670,7 +670,7 @@ func TestCVESort(t *testing.T) {
 		str = space.ReplaceAllString(buff.String(), " ")
 		actual = strings.TrimSpace(str)
 		So(actual, ShouldResemble,
-			"ID SEVERITY TITLE "+
+			"CRITICAL 1, HIGH 1, MEDIUM 2, LOW 1, UNKNOWN 0, TOTAL 5 ID SEVERITY TITLE "+
 				"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ... "+
 				"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
 				"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
diff --git a/pkg/cli/client/image_cmd_internal_test.go b/pkg/cli/client/image_cmd_internal_test.go
index 2387ec61d..cfbf36d34 100644
--- a/pkg/cli/client/image_cmd_internal_test.go
+++ b/pkg/cli/client/image_cmd_internal_test.go
@@ -384,11 +384,13 @@ func TestOutputFormat(t *testing.T) {
 			`"lastUpdated":"0001-01-01T00:00:00Z","size":"123445","platform":{"os":"os","arch":"arch",`+
 			`"variant":""},"isSigned":false,"downloadCount":0,`+
 			`"layers":[{"size":"","digest":"sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6",`+
-			`"score":0}],"history":null,"vulnerabilities":{"maxSeverity":"","count":0},`+
+			`"score":0}],"history":null,"vulnerabilities":{"maxSeverity":"","unknownCount":0,"lowCount":0,`+
+			`"mediumCount":0,"highCount":0,"criticalCount":0,"count":0},`+
 			`"referrers":null,"artifactType":"","signatureInfo":null}],"size":"123445",`+
 			`"downloadCount":0,"lastUpdated":"0001-01-01T00:00:00Z","description":"","isSigned":false,"licenses":"",`+
 			`"labels":"","title":"","source":"","documentation":"","authors":"","vendor":"",`+
-			`"vulnerabilities":{"maxSeverity":"","count":0},"referrers":null,"signatureInfo":null}`+"\n")
+			`"vulnerabilities":{"maxSeverity":"","unknownCount":0,"lowCount":0,"mediumCount":0,"highCount":0,`+
+			`"criticalCount":0,"count":0},"referrers":null,"signatureInfo":null}`+"\n")
 		So(err, ShouldBeNil)
 	})
 
@@ -415,10 +417,13 @@ func TestOutputFormat(t *testing.T) {
 				`lastupdated: 0001-01-01T00:00:00Z size: "123445" platform: os: os arch: arch variant: "" `+
 				`issigned: false downloadcount: 0 layers: - size: "" `+
 				`digest: sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6 score: 0 `+
-				`history: [] vulnerabilities: maxseverity: "" count: 0 referrers: [] artifacttype: "" `+
+				`history: [] vulnerabilities: maxseverity: "" `+
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 `+
+				`referrers: [] artifacttype: "" `+
 				`signatureinfo: [] size: "123445" downloadcount: 0 `+
 				`lastupdated: 0001-01-01T00:00:00Z description: "" issigned: false licenses: "" labels: "" `+
 				`title: "" source: "" documentation: "" authors: "" vendor: "" vulnerabilities: maxseverity: "" `+
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 `+
 				`count: 0 referrers: [] signatureinfo: []`,
 		)
 		So(err, ShouldBeNil)
@@ -449,11 +454,13 @@ func TestOutputFormat(t *testing.T) {
 					`lastupdated: 0001-01-01T00:00:00Z size: "123445" platform: os: os arch: arch variant: "" `+
 					`issigned: false downloadcount: 0 layers: - size: "" `+
 					`digest: sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6 score: 0 `+
-					`history: [] vulnerabilities: maxseverity: "" count: 0 referrers: [] artifacttype: "" `+
+					`history: [] vulnerabilities: maxseverity: "" unknowncount: 0 lowcount: 0 mediumcount: 0 `+
+					`highcount: 0 criticalcount: 0 count: 0 referrers: [] artifacttype: "" `+
 					`signatureinfo: [] size: "123445" downloadcount: 0 `+
 					`lastupdated: 0001-01-01T00:00:00Z description: "" issigned: false licenses: "" labels: "" `+
-					`title: "" source: "" documentation: "" authors: "" vendor: "" vulnerabilities: maxseverity: `+
-					`"" count: 0 referrers: [] signatureinfo: []`,
+					`title: "" source: "" documentation: "" authors: "" vendor: "" vulnerabilities: maxseverity: "" `+
+					`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 `+
+					`count: 0 referrers: [] signatureinfo: []`,
 			)
 			So(err, ShouldBeNil)
 		})
@@ -783,6 +790,7 @@ func TestImagesCommandGQL(t *testing.T) {
 			space := regexp.MustCompile(`\s+`)
 			str := space.ReplaceAllString(buff.String(), " ")
 			actual := strings.TrimSpace(str)
+			So(actual, ShouldContainSubstring, "CRITICAL 0, HIGH 1, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 1")
 			So(actual, ShouldContainSubstring, "dummyCVEID HIGH Title of that CVE")
 		})
 
@@ -1342,6 +1350,15 @@ func (service mockService) getCveByImageGQL(ctx context.Context, config SearchCo
 					},
 				},
 			},
+			Summary: common.ImageVulnerabilitySummary{
+				Count:         1,
+				UnknownCount:  0,
+				LowCount:      0,
+				MediumCount:   0,
+				HighCount:     1,
+				CriticalCount: 0,
+				MaxSeverity:   "HIGH",
+			},
 		},
 	}
 
diff --git a/pkg/cli/client/image_cmd_test.go b/pkg/cli/client/image_cmd_test.go
index 496ff0260..6c033c377 100644
--- a/pkg/cli/client/image_cmd_test.go
+++ b/pkg/cli/client/image_cmd_test.go
@@ -379,11 +379,13 @@ func TestOutputFormatGQL(t *testing.T) {
 				`"lastUpdated":"2023-01-01T12:00:00Z","size":"528","platform":{"os":"linux","arch":"amd64",` +
 				`"variant":""},"isSigned":false,"downloadCount":0,"layers":[{"size":"15","digest":` +
 				`"sha256:b8781e8844f5b7bf6f2f8fa343de18ec471c3b278027355bc34c120585ff04f6","score":0}],` +
-				`"history":null,"vulnerabilities":{"maxSeverity":"","count":0},` +
+				`"history":null,"vulnerabilities":{"maxSeverity":"","unknownCount":0,"lowCount":0,"mediumCount":0,` +
+				`"highCount":0,"criticalCount":0,"count":0},` +
 				`"referrers":null,"artifactType":"","signatureInfo":null}],` +
 				`"size":"528","downloadCount":0,"lastUpdated":"2023-01-01T12:00:00Z","description":"","isSigned":false,` +
 				`"licenses":"","labels":"","title":"","source":"","documentation":"","authors":"","vendor":"",` +
-				`"vulnerabilities":{"maxSeverity":"","count":0},"referrers":null,"signatureInfo":null}` + "\n" +
+				`"vulnerabilities":{"maxSeverity":"","unknownCount":0,"lowCount":0,"mediumCount":0,` +
+				`"highCount":0,"criticalCount":0,"count":0},"referrers":null,"signatureInfo":null}` + "\n" +
 				`{"repoName":"repo7","tag":"test:2.0",` +
 				`"digest":"sha256:51e18f508fd7125b0831ff9a22ba74cd79f0b934e77661ff72cfb54896951a06",` +
 				`"mediaType":"application/vnd.oci.image.manifest.v1+json",` +
@@ -392,11 +394,13 @@ func TestOutputFormatGQL(t *testing.T) {
 				`"lastUpdated":"2023-01-01T12:00:00Z","size":"528","platform":{"os":"linux","arch":"amd64",` +
 				`"variant":""},"isSigned":false,"downloadCount":0,"layers":[{"size":"15","digest":` +
 				`"sha256:b8781e8844f5b7bf6f2f8fa343de18ec471c3b278027355bc34c120585ff04f6","score":0}],` +
-				`"history":null,"vulnerabilities":{"maxSeverity":"","count":0},` +
+				`"history":null,"vulnerabilities":{"maxSeverity":"","unknownCount":0,"lowCount":0,"mediumCount":0,` +
+				`"highCount":0,"criticalCount":0,"count":0},` +
 				`"referrers":null,"artifactType":"","signatureInfo":null}],` +
 				`"size":"528","downloadCount":0,"lastUpdated":"2023-01-01T12:00:00Z","description":"","isSigned":false,` +
 				`"licenses":"","labels":"","title":"","source":"","documentation":"","authors":"","vendor":"",` +
-				`"vulnerabilities":{"maxSeverity":"","count":0},"referrers":null,"signatureInfo":null}` + "\n"
+				`"vulnerabilities":{"maxSeverity":"","unknownCount":0,"lowCount":0,"mediumCount":0,` +
+				`"highCount":0,"criticalCount":0,"count":0},"referrers":null,"signatureInfo":null}` + "\n"
 			// Output is supposed to be in json lines format, keep all spaces as is for verification
 			So(buff.String(), ShouldEqual, expectedStr)
 			So(err, ShouldBeNil)
@@ -424,10 +428,13 @@ func TestOutputFormatGQL(t *testing.T) {
 				`issigned: false downloadcount: 0 layers: - size: "15" ` +
 				`digest: sha256:b8781e8844f5b7bf6f2f8fa343de18ec471c3b278027355bc34c120585ff04f6 score: 0 ` +
 				`history: [] vulnerabilities: maxseverity: "" ` +
-				`count: 0 referrers: [] artifacttype: "" signatureinfo: [] ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] artifacttype: "" signatureinfo: [] ` +
 				`size: "528" downloadcount: 0 lastupdated: 2023-01-01T12:00:00Z description: "" ` +
 				`issigned: false licenses: "" labels: "" title: "" source: "" documentation: "" ` +
-				`authors: "" vendor: "" vulnerabilities: maxseverity: "" count: 0 referrers: [] signatureinfo: [] ` +
+				`authors: "" vendor: "" vulnerabilities: maxseverity: "" ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] signatureinfo: [] ` +
 				`--- reponame: repo7 tag: test:2.0 ` +
 				`digest: sha256:51e18f508fd7125b0831ff9a22ba74cd79f0b934e77661ff72cfb54896951a06 ` +
 				`mediatype: application/vnd.oci.image.manifest.v1+json manifests: - ` +
@@ -437,10 +444,13 @@ func TestOutputFormatGQL(t *testing.T) {
 				`issigned: false downloadcount: 0 layers: - size: "15" ` +
 				`digest: sha256:b8781e8844f5b7bf6f2f8fa343de18ec471c3b278027355bc34c120585ff04f6 score: 0 ` +
 				`history: [] vulnerabilities: maxseverity: "" ` +
-				`count: 0 referrers: [] artifacttype: "" signatureinfo: [] ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] artifacttype: "" signatureinfo: [] ` +
 				`size: "528" downloadcount: 0 lastupdated: 2023-01-01T12:00:00Z description: "" ` +
 				`issigned: false licenses: "" labels: "" title: "" source: "" documentation: "" ` +
-				`authors: "" vendor: "" vulnerabilities: maxseverity: "" count: 0 referrers: [] signatureinfo: []`
+				`authors: "" vendor: "" vulnerabilities: maxseverity: "" ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] signatureinfo: []`
 			So(strings.TrimSpace(str), ShouldEqual, expectedStr)
 			So(err, ShouldBeNil)
 		})
@@ -467,11 +477,13 @@ func TestOutputFormatGQL(t *testing.T) {
 				`issigned: false downloadcount: 0 layers: - size: "15" ` +
 				`digest: sha256:b8781e8844f5b7bf6f2f8fa343de18ec471c3b278027355bc34c120585ff04f6 score: 0 ` +
 				`history: [] vulnerabilities: maxseverity: "" ` +
-				`count: 0 referrers: [] artifacttype: "" signatureinfo: [] ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] artifacttype: "" signatureinfo: [] ` +
 				`size: "528" downloadcount: 0 lastupdated: 2023-01-01T12:00:00Z description: "" ` +
 				`issigned: false licenses: "" labels: "" title: "" source: "" documentation: "" ` +
 				`authors: "" vendor: "" vulnerabilities: maxseverity: "" ` +
-				`count: 0 referrers: [] signatureinfo: [] ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] signatureinfo: [] ` +
 				`--- reponame: repo7 tag: test:2.0 ` +
 				`digest: sha256:51e18f508fd7125b0831ff9a22ba74cd79f0b934e77661ff72cfb54896951a06 ` +
 				`mediatype: application/vnd.oci.image.manifest.v1+json manifests: - ` +
@@ -481,10 +493,13 @@ func TestOutputFormatGQL(t *testing.T) {
 				`issigned: false downloadcount: 0 layers: - size: "15" ` +
 				`digest: sha256:b8781e8844f5b7bf6f2f8fa343de18ec471c3b278027355bc34c120585ff04f6 score: 0 ` +
 				`history: [] vulnerabilities: maxseverity: "" ` +
-				`count: 0 referrers: [] artifacttype: "" signatureinfo: [] ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] artifacttype: "" signatureinfo: [] ` +
 				`size: "528" downloadcount: 0 lastupdated: 2023-01-01T12:00:00Z description: "" ` +
 				`issigned: false licenses: "" labels: "" title: "" source: "" documentation: "" ` +
-				`authors: "" vendor: "" vulnerabilities: maxseverity: "" count: 0 referrers: [] signatureinfo: []`
+				`authors: "" vendor: "" vulnerabilities: maxseverity: "" ` +
+				`unknowncount: 0 lowcount: 0 mediumcount: 0 highcount: 0 criticalcount: 0 count: 0 ` +
+				`referrers: [] signatureinfo: []`
 			So(strings.TrimSpace(str), ShouldEqual, expectedStr)
 			So(err, ShouldBeNil)
 		})
diff --git a/pkg/cli/client/search_functions.go b/pkg/cli/client/search_functions.go
index 9cf5c34f0..dc47b3422 100644
--- a/pkg/cli/client/search_functions.go
+++ b/pkg/cli/client/search_functions.go
@@ -245,6 +245,14 @@ func SearchCVEForImageGQL(config SearchConfig, image, searchedCveID string) erro
 	var builder strings.Builder
 
 	if config.OutputFormat == defaultOutputFormat || config.OutputFormat == "" {
+		imageCVESummary := cveList.Data.CVEListForImage.Summary
+
+		statsStr := fmt.Sprintf("CRITICAL %d, HIGH %d, MEDIUM %d, LOW %d, UNKNOWN %d, TOTAL %d\n\n",
+			imageCVESummary.CriticalCount, imageCVESummary.HighCount, imageCVESummary.MediumCount,
+			imageCVESummary.LowCount, imageCVESummary.UnknownCount, imageCVESummary.Count)
+
+		fmt.Fprint(config.ResultWriter, statsStr)
+
 		printCVETableHeader(&builder)
 		fmt.Fprint(config.ResultWriter, builder.String())
 	}
diff --git a/pkg/cli/client/search_functions_internal_test.go b/pkg/cli/client/search_functions_internal_test.go
index f8880e7e8..4fcb6d15a 100644
--- a/pkg/cli/client/search_functions_internal_test.go
+++ b/pkg/cli/client/search_functions_internal_test.go
@@ -346,6 +346,15 @@ func TestSearchCVEForImageGQL(t *testing.T) {
 									},
 								},
 							},
+							Summary: common.ImageVulnerabilitySummary{
+								Count:         1,
+								UnknownCount:  0,
+								LowCount:      0,
+								MediumCount:   0,
+								HighCount:     1,
+								CriticalCount: 0,
+								MaxSeverity:   "HIGH",
+							},
 						},
 					},
 				}, nil
@@ -357,6 +366,7 @@ func TestSearchCVEForImageGQL(t *testing.T) {
 		space := regexp.MustCompile(`\s+`)
 		str := space.ReplaceAllString(buff.String(), " ")
 		actual := strings.TrimSpace(str)
+		So(actual, ShouldContainSubstring, "CRITICAL 0, HIGH 1, MEDIUM 0, LOW 0, UNKNOWN 0, TOTAL 1")
 		So(actual, ShouldContainSubstring, "dummyCVEID HIGH Title of that CVE")
 	})
 
diff --git a/pkg/cli/client/service.go b/pkg/cli/client/service.go
index a71ed759d..9dbae1bb8 100644
--- a/pkg/cli/client/service.go
+++ b/pkg/cli/client/service.go
@@ -305,10 +305,14 @@ func (service searchService) getCveByImageGQL(ctx context.Context, config Search
 	query := fmt.Sprintf(`
 	{
 		CVEListForImage (image:"%s", searchedCVE:"%s", requestedPage: {sortBy: %s}) {
-			Tag CVEList {
+			Tag
+			CVEList {
 				Id Title Severity Description
 				PackageList {Name InstalledVersion FixedVersion}
 			}
+			Summary {
+				Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity
+			}
 		}
 	}`, imageName, searchedCVE, Flag2SortCriteria(config.SortBy))
 	result := &cveResult{}
@@ -743,8 +747,9 @@ type cve struct {
 
 //nolint:tagliatelle // graphQL schema
 type cveListForImage struct {
-	Tag     string `json:"Tag"`
-	CVEList []cve  `json:"CVEList"`
+	Tag     string                           `json:"Tag"`
+	CVEList []cve                            `json:"CVEList"`
+	Summary common.ImageVulnerabilitySummary `json:"Summary"`
 }
 
 //nolint:tagliatelle // graphQL schema
diff --git a/pkg/common/model.go b/pkg/common/model.go
index cacfc1f54..6c0a7aef2 100644
--- a/pkg/common/model.go
+++ b/pkg/common/model.go
@@ -84,8 +84,13 @@ type Platform struct {
 }
 
 type ImageVulnerabilitySummary struct {
-	MaxSeverity string `json:"maxSeverity"`
-	Count       int    `json:"count"`
+	MaxSeverity   string `json:"maxSeverity"`
+	UnknownCount  int    `json:"unknownCount"`
+	LowCount      int    `json:"lowCount"`
+	MediumCount   int    `json:"mediumCount"`
+	HighCount     int    `json:"highCount"`
+	CriticalCount int    `json:"criticalCount"`
+	Count         int    `json:"count"`
 }
 
 type LayerSummary struct {
diff --git a/pkg/extensions/search/convert/convert_internal_test.go b/pkg/extensions/search/convert/convert_internal_test.go
index d23053729..62826c3ed 100644
--- a/pkg/extensions/search/convert/convert_internal_test.go
+++ b/pkg/extensions/search/convert/convert_internal_test.go
@@ -88,6 +88,11 @@ func TestCVEConvert(t *testing.T) {
 
 			So(imageSummary.Vulnerabilities, ShouldNotBeNil)
 			So(*imageSummary.Vulnerabilities.Count, ShouldEqual, 0)
+			So(*imageSummary.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+			So(*imageSummary.Vulnerabilities.LowCount, ShouldEqual, 0)
+			So(*imageSummary.Vulnerabilities.MediumCount, ShouldEqual, 0)
+			So(*imageSummary.Vulnerabilities.HighCount, ShouldEqual, 0)
+			So(*imageSummary.Vulnerabilities.CriticalCount, ShouldEqual, 0)
 			So(*imageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
 			So(graphql.GetErrors(ctx), ShouldBeNil)
 
@@ -102,20 +107,35 @@ func TestCVEConvert(t *testing.T) {
 					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
 					) (cvemodel.ImageCVESummary, error) {
 						return cvemodel.ImageCVESummary{
-							Count:       1,
-							MaxSeverity: "HIGH",
+							Count:         30,
+							UnknownCount:  1,
+							LowCount:      2,
+							MediumCount:   3,
+							HighCount:     10,
+							CriticalCount: 14,
+							MaxSeverity:   "HIGH",
 						}, nil
 					},
 				},
 			)
 
 			So(imageSummary.Vulnerabilities, ShouldNotBeNil)
-			So(*imageSummary.Vulnerabilities.Count, ShouldEqual, 1)
+			So(*imageSummary.Vulnerabilities.Count, ShouldEqual, 30)
+			So(*imageSummary.Vulnerabilities.UnknownCount, ShouldEqual, 1)
+			So(*imageSummary.Vulnerabilities.LowCount, ShouldEqual, 2)
+			So(*imageSummary.Vulnerabilities.MediumCount, ShouldEqual, 3)
+			So(*imageSummary.Vulnerabilities.HighCount, ShouldEqual, 10)
+			So(*imageSummary.Vulnerabilities.CriticalCount, ShouldEqual, 14)
 			So(*imageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
 			So(graphql.GetErrors(ctx), ShouldBeNil)
 			So(len(imageSummary.Manifests), ShouldEqual, 1)
 			So(imageSummary.Manifests[0].Vulnerabilities, ShouldNotBeNil)
-			So(*imageSummary.Manifests[0].Vulnerabilities.Count, ShouldEqual, 1)
+			So(*imageSummary.Manifests[0].Vulnerabilities.Count, ShouldEqual, 30)
+			So(*imageSummary.Manifests[0].Vulnerabilities.UnknownCount, ShouldEqual, 1)
+			So(*imageSummary.Manifests[0].Vulnerabilities.LowCount, ShouldEqual, 2)
+			So(*imageSummary.Manifests[0].Vulnerabilities.MediumCount, ShouldEqual, 3)
+			So(*imageSummary.Manifests[0].Vulnerabilities.HighCount, ShouldEqual, 10)
+			So(*imageSummary.Manifests[0].Vulnerabilities.CriticalCount, ShouldEqual, 14)
 			So(*imageSummary.Manifests[0].Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
 
 			imageSummary.Vulnerabilities = nil
@@ -152,8 +172,13 @@ func TestCVEConvert(t *testing.T) {
 					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
 					) (cvemodel.ImageCVESummary, error) {
 						return cvemodel.ImageCVESummary{
-							Count:       1,
-							MaxSeverity: "HIGH",
+							Count:         30,
+							UnknownCount:  1,
+							LowCount:      2,
+							MediumCount:   3,
+							HighCount:     10,
+							CriticalCount: 14,
+							MaxSeverity:   "HIGH",
 						}, nil
 					},
 				},
@@ -182,15 +207,25 @@ func TestCVEConvert(t *testing.T) {
 					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
 					) (cvemodel.ImageCVESummary, error) {
 						return cvemodel.ImageCVESummary{
-							Count:       1,
-							MaxSeverity: "HIGH",
+							Count:         30,
+							UnknownCount:  1,
+							LowCount:      2,
+							MediumCount:   3,
+							HighCount:     10,
+							CriticalCount: 14,
+							MaxSeverity:   "HIGH",
 						}, nil
 					},
 				},
 			)
 
 			So(repoSummary.NewestImage.Vulnerabilities, ShouldNotBeNil)
-			So(*repoSummary.NewestImage.Vulnerabilities.Count, ShouldEqual, 1)
+			So(*repoSummary.NewestImage.Vulnerabilities.Count, ShouldEqual, 30)
+			So(*repoSummary.NewestImage.Vulnerabilities.UnknownCount, ShouldEqual, 1)
+			So(*repoSummary.NewestImage.Vulnerabilities.LowCount, ShouldEqual, 2)
+			So(*repoSummary.NewestImage.Vulnerabilities.MediumCount, ShouldEqual, 3)
+			So(*repoSummary.NewestImage.Vulnerabilities.HighCount, ShouldEqual, 10)
+			So(*repoSummary.NewestImage.Vulnerabilities.CriticalCount, ShouldEqual, 14)
 			So(*repoSummary.NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
 			So(graphql.GetErrors(ctx), ShouldBeNil)
 		})
@@ -251,15 +286,25 @@ func TestCVEConvert(t *testing.T) {
 					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
 					) (cvemodel.ImageCVESummary, error) {
 						return cvemodel.ImageCVESummary{
-							Count:       1,
-							MaxSeverity: "HIGH",
+							Count:         30,
+							UnknownCount:  1,
+							LowCount:      2,
+							MediumCount:   3,
+							HighCount:     10,
+							CriticalCount: 14,
+							MaxSeverity:   "HIGH",
 						}, nil
 					},
 				},
 			)
 
 			So(manifestSummary.Vulnerabilities, ShouldNotBeNil)
-			So(*manifestSummary.Vulnerabilities.Count, ShouldEqual, 1)
+			So(*manifestSummary.Vulnerabilities.Count, ShouldEqual, 30)
+			So(*manifestSummary.Vulnerabilities.UnknownCount, ShouldEqual, 1)
+			So(*manifestSummary.Vulnerabilities.LowCount, ShouldEqual, 2)
+			So(*manifestSummary.Vulnerabilities.MediumCount, ShouldEqual, 3)
+			So(*manifestSummary.Vulnerabilities.HighCount, ShouldEqual, 10)
+			So(*manifestSummary.Vulnerabilities.CriticalCount, ShouldEqual, 14)
 			So(*manifestSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
 
 			manifestSummary.Vulnerabilities = nil
diff --git a/pkg/extensions/search/convert/cve.go b/pkg/extensions/search/convert/cve.go
index ffda72088..282c0f1d6 100644
--- a/pkg/extensions/search/convert/cve.go
+++ b/pkg/extensions/search/convert/cve.go
@@ -38,8 +38,13 @@ func updateImageSummaryVulnerabilities(
 	imageCveSummary := cvemodel.ImageCVESummary{}
 
 	imageSummary.Vulnerabilities = &gql_generated.ImageVulnerabilitySummary{
-		MaxSeverity: &imageCveSummary.MaxSeverity,
-		Count:       &imageCveSummary.Count,
+		MaxSeverity:   &imageCveSummary.MaxSeverity,
+		UnknownCount:  &imageCveSummary.UnknownCount,
+		LowCount:      &imageCveSummary.LowCount,
+		MediumCount:   &imageCveSummary.MediumCount,
+		HighCount:     &imageCveSummary.HighCount,
+		CriticalCount: &imageCveSummary.CriticalCount,
+		Count:         &imageCveSummary.Count,
 	}
 
 	// Check if vulnerability scanning is disabled
@@ -61,6 +66,11 @@ func updateImageSummaryVulnerabilities(
 	}
 
 	imageSummary.Vulnerabilities.MaxSeverity = &imageCveSummary.MaxSeverity
+	imageSummary.Vulnerabilities.UnknownCount = &imageCveSummary.UnknownCount
+	imageSummary.Vulnerabilities.LowCount = &imageCveSummary.LowCount
+	imageSummary.Vulnerabilities.MediumCount = &imageCveSummary.MediumCount
+	imageSummary.Vulnerabilities.HighCount = &imageCveSummary.HighCount
+	imageSummary.Vulnerabilities.CriticalCount = &imageCveSummary.CriticalCount
 	imageSummary.Vulnerabilities.Count = &imageCveSummary.Count
 
 	for _, manifestSummary := range imageSummary.Manifests {
@@ -82,8 +92,13 @@ func updateManifestSummaryVulnerabilities(
 	imageCveSummary := cvemodel.ImageCVESummary{}
 
 	manifestSummary.Vulnerabilities = &gql_generated.ImageVulnerabilitySummary{
-		MaxSeverity: &imageCveSummary.MaxSeverity,
-		Count:       &imageCveSummary.Count,
+		MaxSeverity:   &imageCveSummary.MaxSeverity,
+		UnknownCount:  &imageCveSummary.UnknownCount,
+		LowCount:      &imageCveSummary.LowCount,
+		MediumCount:   &imageCveSummary.MediumCount,
+		HighCount:     &imageCveSummary.HighCount,
+		CriticalCount: &imageCveSummary.CriticalCount,
+		Count:         &imageCveSummary.Count,
 	}
 
 	// Check if vulnerability scanning is disabled
@@ -105,5 +120,10 @@ func updateManifestSummaryVulnerabilities(
 	}
 
 	manifestSummary.Vulnerabilities.MaxSeverity = &imageCveSummary.MaxSeverity
+	manifestSummary.Vulnerabilities.UnknownCount = &imageCveSummary.UnknownCount
+	manifestSummary.Vulnerabilities.LowCount = &imageCveSummary.LowCount
+	manifestSummary.Vulnerabilities.MediumCount = &imageCveSummary.MediumCount
+	manifestSummary.Vulnerabilities.HighCount = &imageCveSummary.HighCount
+	manifestSummary.Vulnerabilities.CriticalCount = &imageCveSummary.CriticalCount
 	manifestSummary.Vulnerabilities.Count = &imageCveSummary.Count
 }
diff --git a/pkg/extensions/search/cve/cve.go b/pkg/extensions/search/cve/cve.go
index da2dcb718..c28995873 100644
--- a/pkg/extensions/search/cve/cve.go
+++ b/pkg/extensions/search/cve/cve.go
@@ -23,8 +23,8 @@ type CveInfo interface {
 	GetImageListForCVE(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
 	GetImageListWithCVEFixed(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
 	GetCVEListForImage(ctx context.Context, repo, tag string, searchedCVE string, pageinput cvemodel.PageInput,
-	) ([]cvemodel.CVE, zcommon.PageInfo, error)
-	GetCVESummaryForImageMedia(ctx context.Context, repo, digest, mediaType string) (cvemodel.ImageCVESummary, error)
+	) ([]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error)
+	GetCVESummaryForImageMedia(ctx context.Context, repo, digestStr, mediaType string) (cvemodel.ImageCVESummary, error)
 }
 
 type Scanner interface {
@@ -352,75 +352,67 @@ func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE string, pageFinde
 func (cveinfo BaseCveInfo) GetCVEListForImage(ctx context.Context, repo, ref string, searchedCVE string,
 	pageInput cvemodel.PageInput,
 ) (
-	[]cvemodel.CVE, zcommon.PageInfo, error,
+	[]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error,
 ) {
+	imageCVESummary := cvemodel.ImageCVESummary{
+		MaxSeverity: cvemodel.SeverityNotScanned,
+	}
+
 	isValidImage, err := cveinfo.Scanner.IsImageFormatScannable(repo, ref)
 	if !isValidImage {
 		cveinfo.Log.Debug().Str("image", repo+":"+ref).Err(err).Msg("image is not scanable")
 
-		return []cvemodel.CVE{}, zcommon.PageInfo{}, err
+		return []cvemodel.CVE{}, imageCVESummary, zcommon.PageInfo{}, err
 	}
 
 	image := zcommon.GetFullImageName(repo, ref)
 
 	cveMap, err := cveinfo.Scanner.ScanImage(ctx, image)
 	if err != nil {
-		return []cvemodel.CVE{}, zcommon.PageInfo{}, err
+		return []cvemodel.CVE{}, imageCVESummary, zcommon.PageInfo{}, err
 	}
 
+	imageCVESummary = initCVESummaryFromCVEMap(cveMap)
+
 	pageFinder, err := NewCvePageFinder(pageInput.Limit, pageInput.Offset, pageInput.SortBy)
 	if err != nil {
-		return []cvemodel.CVE{}, zcommon.PageInfo{}, err
+		return []cvemodel.CVE{}, imageCVESummary, zcommon.PageInfo{}, err
 	}
 
 	filterCVEList(cveMap, searchedCVE, pageFinder)
 
 	cveList, pageInfo := pageFinder.Page()
 
-	return cveList, pageInfo, nil
+	return cveList, imageCVESummary, pageInfo, nil
 }
 
-func (cveinfo BaseCveInfo) GetCVESummaryForImageMedia(ctx context.Context, repo, digest, mediaType string,
+func (cveinfo BaseCveInfo) GetCVESummaryForImageMedia(ctx context.Context, repo, digestStr, mediaType string,
 ) (cvemodel.ImageCVESummary, error) {
 	// There are several cases, expected returned values below:
 	// not scanned yet                     - max severity ""            - cve count 0   - no Errors
 	// not scannable                       - max severity ""            - cve count 0   - has Errors
 	// scannable no issues found           - max severity "NONE"        - cve count 0   - no Errors
 	// scannable issues found              - max severity from Scanner  - cve count >0  - no Errors
-	imageCVESummary := cvemodel.ImageCVESummary{
-		Count:       0,
-		MaxSeverity: cvemodel.SeverityNotScanned,
-	}
-
 	// For this call we only look at the scanner cache, we skip the actual scanning to save time
-	if !cveinfo.Scanner.IsResultCached(digest) {
-		isValidImage, err := cveinfo.Scanner.IsImageMediaScannable(repo, digest, mediaType)
+	if !cveinfo.Scanner.IsResultCached(digestStr) {
+		isValidImage, err := cveinfo.Scanner.IsImageMediaScannable(repo, digestStr, mediaType)
 		if !isValidImage {
-			cveinfo.Log.Debug().Str("digest", digest).Str("mediaType", mediaType).
+			cveinfo.Log.Debug().Str("digest", digestStr).Str("mediaType", mediaType).
 				Err(err).Msg("image is not scannable")
 		}
 
+		// Counters are initialized with 0 by default
+		imageCVESummary := cvemodel.ImageCVESummary{
+			MaxSeverity: cvemodel.SeverityNotScanned,
+		}
+
 		return imageCVESummary, err
 	}
 
 	// We will make due with cached results
-	cveMap := cveinfo.Scanner.GetCachedResult(digest)
-
-	imageCVESummary.Count = len(cveMap)
-	if imageCVESummary.Count == 0 {
-		imageCVESummary.MaxSeverity = cvemodel.SeverityNone
-
-		return imageCVESummary, nil
-	}
-
-	imageCVESummary.MaxSeverity = cvemodel.SeverityUnknown
-	for _, cve := range cveMap {
-		if cvemodel.CompareSeverities(imageCVESummary.MaxSeverity, cve.Severity) > 0 {
-			imageCVESummary.MaxSeverity = cve.Severity
-		}
-	}
+	cveMap := cveinfo.Scanner.GetCachedResult(digestStr)
 
-	return imageCVESummary, nil
+	return initCVESummaryFromCVEMap(cveMap), nil
 }
 
 func GetFixedTags(allTags, vulnerableTags []cvemodel.TagInfo) []cvemodel.TagInfo {
@@ -517,3 +509,40 @@ func containsDescriptorInfo(slice []cvemodel.DescriptorInfo, descriptorInfo cvem
 
 	return false
 }
+
+func initCVESummaryFromCVEMap(cveMap map[string]cvemodel.CVE) cvemodel.ImageCVESummary {
+	// Counters are initialized with 0 by default
+	imageCVESummary := cvemodel.ImageCVESummary{
+		MaxSeverity: cvemodel.SeverityNotScanned,
+	}
+
+	imageCVESummary.Count = len(cveMap)
+	if imageCVESummary.Count == 0 {
+		imageCVESummary.MaxSeverity = cvemodel.SeverityNone
+
+		return imageCVESummary
+	}
+
+	imageCVESummary.MaxSeverity = cvemodel.SeverityUnknown
+
+	for _, cve := range cveMap {
+		switch cve.Severity {
+		case cvemodel.SeverityUnknown:
+			imageCVESummary.UnknownCount += 1
+		case cvemodel.SeverityLow:
+			imageCVESummary.LowCount += 1
+		case cvemodel.SeverityMedium:
+			imageCVESummary.MediumCount += 1
+		case cvemodel.SeverityHigh:
+			imageCVESummary.HighCount += 1
+		case cvemodel.SeverityCritical:
+			imageCVESummary.CriticalCount += 1
+		}
+
+		if cvemodel.CompareSeverities(imageCVESummary.MaxSeverity, cve.Severity) > 0 {
+			imageCVESummary.MaxSeverity = cve.Severity
+		}
+	}
+
+	return imageCVESummary
+}
diff --git a/pkg/extensions/search/cve/cve_test.go b/pkg/extensions/search/cve/cve_test.go
index fd9e277da..add2640e7 100644
--- a/pkg/extensions/search/cve/cve_test.go
+++ b/pkg/extensions/search/cve/cve_test.go
@@ -754,6 +754,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 		const repo5 = "repo5"
 		const repo6 = "repo6"
 		const repo7 = "repo7"
+		const repo8 = "repo8"
 		const repo100 = "repo100"
 		const repoMultiarch = "repoIndex"
 
@@ -833,6 +834,13 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 		err = metaDB.SetRepoReference(context.Background(), repo7, "1.0.0", image71.AsImageMeta())
 		So(err, ShouldBeNil)
 
+		// Create image with vulnerabilities of all severities
+		image81 := CreateImageWith().DefaultLayers().
+			ImageConfig(ispec.Image{Created: DateRef(2020, 12, 1, 12, 0, 0, 0, time.UTC)}).Build()
+
+		err = metaDB.SetRepoReference(context.Background(), repo8, "1.0.0", image81.AsImageMeta())
+		So(err, ShouldBeNil)
+
 		// create multiarch image with vulnerabilities
 		multiarchImage := CreateRandomMultiarch()
 
@@ -891,6 +899,10 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 		image71Media := image71.ManifestDescriptor.MediaType
 		image71Name := repo7 + ":1.0.0"
 		imageMap[image71Name] = image71Digest
+		image81Digest := image81.ManifestDescriptor.Digest.String()
+		image81Media := image81.ManifestDescriptor.MediaType
+		image81Name := repo8 + ":1.0.0"
+		imageMap[image81Name] = image81Digest
 		indexDigest := multiarchImage.IndexDescriptor.Digest.String()
 		indexMedia := multiarchImage.IndexDescriptor.MediaType
 		indexName := repoMultiarch + ":tagIndex"
@@ -1042,6 +1054,57 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 					return result, nil
 				}
 
+				if repo == repo8 && ref == image81Digest {
+					result := map[string]cvemodel.CVE{
+						"CVE0": {
+							ID:          "CVE0",
+							Severity:    "UNKNOWN",
+							Title:       "Title CVE0",
+							Description: "Description CVE0",
+						},
+						"CVE1": {
+							ID:          "CVE1",
+							Severity:    "MEDIUM",
+							Title:       "Title CVE1",
+							Description: "Description CVE1",
+						},
+						"CVE2": {
+							ID:          "CVE2",
+							Severity:    "HIGH",
+							Title:       "Title CVE2",
+							Description: "Description CVE2",
+						},
+						"CVE3": {
+							ID:          "CVE3",
+							Severity:    "LOW",
+							Title:       "Title CVE3",
+							Description: "Description CVE3",
+						},
+						"CVE4": {
+							ID:          "CVE4",
+							Severity:    "CRITICAL",
+							Title:       "Title CVE4",
+							Description: "Description CVE4",
+						},
+						"CVE5": {
+							ID:          "CVE5",
+							Severity:    "CRITICAL",
+							Title:       "Title CVE5",
+							Description: "Description CVE5",
+						},
+						"CVE6": {
+							ID:          "CVE6",
+							Severity:    "LOW",
+							Title:       "Title CVE6",
+							Description: "Description CVE6",
+						},
+					}
+
+					cache.Add(ref, result)
+
+					return result, nil
+				}
+
 				// By default the image has no vulnerabilities
 				result = map[string]cvemodel.CVE{}
 				cache.Add(ref, result)
@@ -1130,14 +1193,21 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 		ctx := context.Background()
 
 		// Image is found
-		cveList, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", pageInput)
 		So(err, ShouldBeNil)
 		So(len(cveList), ShouldEqual, 1)
 		So(cveList[0].ID, ShouldEqual, "CVE1")
 		So(pageInfo.ItemCount, ShouldEqual, 1)
 		So(pageInfo.TotalCount, ShouldEqual, 1)
+		So(cveSummary.Count, ShouldEqual, 1)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
 
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.0", "", pageInput)
 		So(err, ShouldBeNil)
 		So(len(cveList), ShouldEqual, 3)
 		So(cveList[0].ID, ShouldEqual, "CVE2")
@@ -1145,116 +1215,249 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 		So(cveList[2].ID, ShouldEqual, "CVE3")
 		So(pageInfo.ItemCount, ShouldEqual, 3)
 		So(pageInfo.TotalCount, ShouldEqual, 3)
+		So(cveSummary.Count, ShouldEqual, 3)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 1)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 1)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "HIGH")
 
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.1", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.1", "", pageInput)
 		So(err, ShouldBeNil)
 		So(len(cveList), ShouldEqual, 2)
 		So(cveList[0].ID, ShouldEqual, "CVE1")
 		So(cveList[1].ID, ShouldEqual, "CVE3")
 		So(pageInfo.ItemCount, ShouldEqual, 2)
 		So(pageInfo.TotalCount, ShouldEqual, 2)
+		So(cveSummary.Count, ShouldEqual, 2)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 1)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
 
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.1.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.1.0", "", pageInput)
 		So(err, ShouldBeNil)
 		So(len(cveList), ShouldEqual, 1)
 		So(cveList[0].ID, ShouldEqual, "CVE3")
 		So(pageInfo.ItemCount, ShouldEqual, 1)
 		So(pageInfo.TotalCount, ShouldEqual, 1)
+		So(cveSummary.Count, ShouldEqual, 1)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 1)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "LOW")
 
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo6, "1.0.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo6, "1.0.0", "", pageInput)
 		So(err, ShouldBeNil)
 		So(len(cveList), ShouldEqual, 0)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "NONE")
+
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo8, "1.0.0", "", pageInput)
+		So(err, ShouldBeNil)
+		So(len(cveList), ShouldEqual, 7)
+		So(pageInfo.ItemCount, ShouldEqual, 7)
+		So(pageInfo.TotalCount, ShouldEqual, 7)
+		So(cveSummary.Count, ShouldEqual, 7)
+		So(cveSummary.UnknownCount, ShouldEqual, 1)
+		So(cveSummary.LowCount, ShouldEqual, 2)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 1)
+		So(cveSummary.CriticalCount, ShouldEqual, 2)
+		So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 
 		// Image is multiarch
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repoMultiarch, "tagIndex", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repoMultiarch, "tagIndex", "", pageInput)
 		So(err, ShouldBeNil)
 		So(len(cveList), ShouldEqual, 1)
 		So(cveList[0].ID, ShouldEqual, "CVE1")
 		So(pageInfo.ItemCount, ShouldEqual, 1)
 		So(pageInfo.TotalCount, ShouldEqual, 1)
+		So(cveSummary.Count, ShouldEqual, 1)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
 
 		// Image is not scannable
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo2, "1.0.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo2, "1.0.0", "", pageInput)
 		So(err, ShouldEqual, zerr.ErrScanNotSupported)
 		So(len(cveList), ShouldEqual, 0)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// Tag is not found
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo3, "1.0.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo3, "1.0.0", "", pageInput)
 		So(err, ShouldEqual, zerr.ErrTagMetaNotFound)
 		So(len(cveList), ShouldEqual, 0)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// Scan failed
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo7, "1.0.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo7, "1.0.0", "", pageInput)
 		So(err, ShouldEqual, ErrFailedScan)
 		So(len(cveList), ShouldEqual, 0)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// Tag is not found
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo-with-bad-tag-digest", "tag", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo-with-bad-tag-digest", "tag", "", pageInput)
 		So(err, ShouldEqual, zerr.ErrImageMetaNotFound)
 		So(len(cveList), ShouldEqual, 0)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// Repo is not found
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo100, "1.0.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo100, "1.0.0", "", pageInput)
 		So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
 		So(len(cveList), ShouldEqual, 0)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// By this point the cache should already be pupulated by previous function calls
 		t.Log("\nTest GetCVESummaryForImage\n")
 
 		// Image is found
-		cveSummary, err := cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image11Digest, image11Media)
+		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image11Digest, image11Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 1)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
 
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image12Digest, image12Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 3)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 1)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 1)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "HIGH")
 
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image14Digest, image14Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 2)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 1)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
 
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image13Digest, image13Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 1)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 1)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "LOW")
 
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo6, image61Digest, image61Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "NONE")
 
+		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo8, image81Digest, image81Media)
+		So(err, ShouldBeNil)
+		So(cveSummary.Count, ShouldEqual, 7)
+		So(cveSummary.UnknownCount, ShouldEqual, 1)
+		So(cveSummary.LowCount, ShouldEqual, 2)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 1)
+		So(cveSummary.CriticalCount, ShouldEqual, 2)
+		So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
+
 		// Image is multiarch
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repoMultiarch, indexDigest, indexMedia)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 1)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 1)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
 
 		// Image is not scannable
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo2, image21Digest, image21Media)
 		So(err, ShouldEqual, zerr.ErrScanNotSupported)
 		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// Scan failed
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo5, image71Digest, image71Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		// Repo is not found
@@ -1262,6 +1465,11 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 			godigest.FromString("missing_digest").String(), ispec.MediaTypeImageManifest)
 		So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
 		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		t.Log("\nTest GetImageListWithCVEFixed\n")
@@ -1366,13 +1574,25 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
 		cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image11Digest, image11Media)
 		So(err, ShouldBeNil)
 		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
 		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
-		cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", pageInput)
+		cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", pageInput)
 		So(err, ShouldNotBeNil)
 		So(cveList, ShouldBeEmpty)
 		So(pageInfo.ItemCount, ShouldEqual, 0)
 		So(pageInfo.TotalCount, ShouldEqual, 0)
+		So(cveSummary.Count, ShouldEqual, 0)
+		So(cveSummary.UnknownCount, ShouldEqual, 0)
+		So(cveSummary.LowCount, ShouldEqual, 0)
+		So(cveSummary.MediumCount, ShouldEqual, 0)
+		So(cveSummary.HighCount, ShouldEqual, 0)
+		So(cveSummary.CriticalCount, ShouldEqual, 0)
+		So(cveSummary.MaxSeverity, ShouldEqual, "")
 
 		tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo1, "CVE1")
 		// CVE is not considered fixed as scan is not possible
diff --git a/pkg/extensions/search/cve/model/models.go b/pkg/extensions/search/cve/model/models.go
index fbc20b517..e85de88c8 100644
--- a/pkg/extensions/search/cve/model/models.go
+++ b/pkg/extensions/search/cve/model/models.go
@@ -7,8 +7,13 @@ import (
 )
 
 type ImageCVESummary struct {
-	Count       int
-	MaxSeverity string
+	Count         int
+	UnknownCount  int
+	LowCount      int
+	MediumCount   int
+	HighCount     int
+	CriticalCount int
+	MaxSeverity   string
 }
 
 //nolint:tagliatelle // graphQL schema
diff --git a/pkg/extensions/search/cve/pagination_test.go b/pkg/extensions/search/cve/pagination_test.go
index a154ddd4d..08f3b8990 100644
--- a/pkg/extensions/search/cve/pagination_test.go
+++ b/pkg/extensions/search/cve/pagination_test.go
@@ -140,22 +140,36 @@ func TestCVEPagination(t *testing.T) {
 		Convey("Page", func() {
 			Convey("defaults", func() {
 				// By default expect unlimitted results sorted by severity
-				cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{})
+				cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{})
 				So(err, ShouldBeNil)
 				So(len(cves), ShouldEqual, 5)
 				So(pageInfo.ItemCount, ShouldEqual, 5)
 				So(pageInfo.TotalCount, ShouldEqual, 5)
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				previousSeverity := 4
 				for _, cve := range cves {
 					So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
 					previousSeverity = severityToInt[cve.Severity]
 				}
 
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{})
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{})
 				So(err, ShouldBeNil)
 				So(len(cves), ShouldEqual, 30)
 				So(pageInfo.ItemCount, ShouldEqual, 30)
 				So(pageInfo.TotalCount, ShouldEqual, 30)
+				So(cveSummary.Count, ShouldEqual, 30)
+				So(cveSummary.UnknownCount, ShouldEqual, 6)
+				So(cveSummary.LowCount, ShouldEqual, 6)
+				So(cveSummary.MediumCount, ShouldEqual, 6)
+				So(cveSummary.HighCount, ShouldEqual, 6)
+				So(cveSummary.CriticalCount, ShouldEqual, 6)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				previousSeverity = 4
 				for _, cve := range cves {
 					So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
@@ -169,44 +183,72 @@ func TestCVEPagination(t *testing.T) {
 					cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
 				}
 
-				cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "",
+				cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "",
 					cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
 				So(err, ShouldBeNil)
 				So(len(cves), ShouldEqual, 5)
 				So(pageInfo.ItemCount, ShouldEqual, 5)
 				So(pageInfo.TotalCount, ShouldEqual, 5)
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				for i, cve := range cves {
 					So(cve.ID, ShouldEqual, cveIds[i])
 				}
 
 				sort.Strings(cveIds)
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
 					cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
 				So(err, ShouldBeNil)
 				So(len(cves), ShouldEqual, 30)
 				So(pageInfo.ItemCount, ShouldEqual, 30)
 				So(pageInfo.TotalCount, ShouldEqual, 30)
+				So(cveSummary.Count, ShouldEqual, 30)
+				So(cveSummary.UnknownCount, ShouldEqual, 6)
+				So(cveSummary.LowCount, ShouldEqual, 6)
+				So(cveSummary.MediumCount, ShouldEqual, 6)
+				So(cveSummary.HighCount, ShouldEqual, 6)
+				So(cveSummary.CriticalCount, ShouldEqual, 6)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				for i, cve := range cves {
 					So(cve.ID, ShouldEqual, cveIds[i])
 				}
 
 				sort.Sort(sort.Reverse(sort.StringSlice(cveIds)))
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
 					cvemodel.PageInput{SortBy: cveinfo.AlphabeticDsc})
 				So(err, ShouldBeNil)
 				So(len(cves), ShouldEqual, 30)
 				So(pageInfo.ItemCount, ShouldEqual, 30)
 				So(pageInfo.TotalCount, ShouldEqual, 30)
+				So(cveSummary.Count, ShouldEqual, 30)
+				So(cveSummary.UnknownCount, ShouldEqual, 6)
+				So(cveSummary.LowCount, ShouldEqual, 6)
+				So(cveSummary.MediumCount, ShouldEqual, 6)
+				So(cveSummary.HighCount, ShouldEqual, 6)
+				So(cveSummary.CriticalCount, ShouldEqual, 6)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				for i, cve := range cves {
 					So(cve.ID, ShouldEqual, cveIds[i])
 				}
 
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
 					cvemodel.PageInput{SortBy: cveinfo.SeverityDsc})
 				So(err, ShouldBeNil)
 				So(len(cves), ShouldEqual, 30)
 				So(pageInfo.ItemCount, ShouldEqual, 30)
 				So(pageInfo.TotalCount, ShouldEqual, 30)
+				So(cveSummary.Count, ShouldEqual, 30)
+				So(cveSummary.UnknownCount, ShouldEqual, 6)
+				So(cveSummary.LowCount, ShouldEqual, 6)
+				So(cveSummary.MediumCount, ShouldEqual, 6)
+				So(cveSummary.HighCount, ShouldEqual, 6)
+				So(cveSummary.CriticalCount, ShouldEqual, 6)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				previousSeverity := 4
 				for _, cve := range cves {
 					So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
@@ -220,7 +262,7 @@ func TestCVEPagination(t *testing.T) {
 					cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
 				}
 
-				cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
+				cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
 					Limit:  3,
 					Offset: 1,
 					SortBy: cveinfo.AlphabeticAsc,
@@ -233,8 +275,15 @@ func TestCVEPagination(t *testing.T) {
 				So(cves[0].ID, ShouldEqual, "CVE1") // CVE0 is first ID and is not part of the page
 				So(cves[1].ID, ShouldEqual, "CVE2")
 				So(cves[2].ID, ShouldEqual, "CVE3")
-
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
+
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
 					Limit:  2,
 					Offset: 1,
 					SortBy: cveinfo.AlphabeticDsc,
@@ -246,8 +295,15 @@ func TestCVEPagination(t *testing.T) {
 				So(pageInfo.TotalCount, ShouldEqual, 5)
 				So(cves[0].ID, ShouldEqual, "CVE3")
 				So(cves[1].ID, ShouldEqual, "CVE2")
-
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
+
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
 					Limit:  3,
 					Offset: 1,
 					SortBy: cveinfo.SeverityDsc,
@@ -257,6 +313,13 @@ func TestCVEPagination(t *testing.T) {
 				So(len(cves), ShouldEqual, 3)
 				So(pageInfo.ItemCount, ShouldEqual, 3)
 				So(pageInfo.TotalCount, ShouldEqual, 5)
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				previousSeverity := 4
 				for _, cve := range cves {
 					So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
@@ -264,7 +327,7 @@ func TestCVEPagination(t *testing.T) {
 				}
 
 				sort.Strings(cveIds)
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{
 					Limit:  5,
 					Offset: 20,
 					SortBy: cveinfo.AlphabeticAsc,
@@ -274,13 +337,20 @@ func TestCVEPagination(t *testing.T) {
 				So(len(cves), ShouldEqual, 5)
 				So(pageInfo.ItemCount, ShouldEqual, 5)
 				So(pageInfo.TotalCount, ShouldEqual, 30)
+				So(cveSummary.Count, ShouldEqual, 30)
+				So(cveSummary.UnknownCount, ShouldEqual, 6)
+				So(cveSummary.LowCount, ShouldEqual, 6)
+				So(cveSummary.MediumCount, ShouldEqual, 6)
+				So(cveSummary.HighCount, ShouldEqual, 6)
+				So(cveSummary.CriticalCount, ShouldEqual, 6)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				for i, cve := range cves {
 					So(cve.ID, ShouldEqual, cveIds[i+20])
 				}
 			})
 
 			Convey("limit > len(cves)", func() {
-				cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
+				cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
 					Limit:  6,
 					Offset: 3,
 					SortBy: cveinfo.AlphabeticAsc,
@@ -292,8 +362,15 @@ func TestCVEPagination(t *testing.T) {
 				So(pageInfo.TotalCount, ShouldEqual, 5)
 				So(cves[0].ID, ShouldEqual, "CVE3")
 				So(cves[1].ID, ShouldEqual, "CVE4")
-
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
+
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
 					Limit:  6,
 					Offset: 3,
 					SortBy: cveinfo.AlphabeticDsc,
@@ -305,8 +382,15 @@ func TestCVEPagination(t *testing.T) {
 				So(pageInfo.TotalCount, ShouldEqual, 5)
 				So(cves[0].ID, ShouldEqual, "CVE1")
 				So(cves[1].ID, ShouldEqual, "CVE0")
-
-				cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
+
+				cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
 					Limit:  6,
 					Offset: 3,
 					SortBy: cveinfo.SeverityDsc,
@@ -316,6 +400,13 @@ func TestCVEPagination(t *testing.T) {
 				So(len(cves), ShouldEqual, 2)
 				So(pageInfo.ItemCount, ShouldEqual, 2)
 				So(pageInfo.TotalCount, ShouldEqual, 5)
+				So(cveSummary.Count, ShouldEqual, 5)
+				So(cveSummary.UnknownCount, ShouldEqual, 1)
+				So(cveSummary.LowCount, ShouldEqual, 1)
+				So(cveSummary.MediumCount, ShouldEqual, 1)
+				So(cveSummary.HighCount, ShouldEqual, 1)
+				So(cveSummary.CriticalCount, ShouldEqual, 1)
+				So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
 				previousSeverity := 4
 				for _, cve := range cves {
 					So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
diff --git a/pkg/extensions/search/gql_generated/generated.go b/pkg/extensions/search/gql_generated/generated.go
index ef3258bd1..9585fc77e 100644
--- a/pkg/extensions/search/gql_generated/generated.go
+++ b/pkg/extensions/search/gql_generated/generated.go
@@ -62,6 +62,7 @@ type ComplexityRoot struct {
 	CVEResultForImage struct {
 		CVEList func(childComplexity int) int
 		Page    func(childComplexity int) int
+		Summary func(childComplexity int) int
 		Tag     func(childComplexity int) int
 	}
 
@@ -105,8 +106,13 @@ type ComplexityRoot struct {
 	}
 
 	ImageVulnerabilitySummary struct {
-		Count       func(childComplexity int) int
-		MaxSeverity func(childComplexity int) int
+		Count         func(childComplexity int) int
+		CriticalCount func(childComplexity int) int
+		HighCount     func(childComplexity int) int
+		LowCount      func(childComplexity int) int
+		MaxSeverity   func(childComplexity int) int
+		MediumCount   func(childComplexity int) int
+		UnknownCount  func(childComplexity int) int
 	}
 
 	LayerHistory struct {
@@ -318,6 +324,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.CVEResultForImage.Page(childComplexity), true
 
+	case "CVEResultForImage.Summary":
+		if e.complexity.CVEResultForImage.Summary == nil {
+			break
+		}
+
+		return e.complexity.CVEResultForImage.Summary(childComplexity), true
+
 	case "CVEResultForImage.Tag":
 		if e.complexity.CVEResultForImage.Tag == nil {
 			break
@@ -542,6 +555,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.ImageVulnerabilitySummary.Count(childComplexity), true
 
+	case "ImageVulnerabilitySummary.CriticalCount":
+		if e.complexity.ImageVulnerabilitySummary.CriticalCount == nil {
+			break
+		}
+
+		return e.complexity.ImageVulnerabilitySummary.CriticalCount(childComplexity), true
+
+	case "ImageVulnerabilitySummary.HighCount":
+		if e.complexity.ImageVulnerabilitySummary.HighCount == nil {
+			break
+		}
+
+		return e.complexity.ImageVulnerabilitySummary.HighCount(childComplexity), true
+
+	case "ImageVulnerabilitySummary.LowCount":
+		if e.complexity.ImageVulnerabilitySummary.LowCount == nil {
+			break
+		}
+
+		return e.complexity.ImageVulnerabilitySummary.LowCount(childComplexity), true
+
 	case "ImageVulnerabilitySummary.MaxSeverity":
 		if e.complexity.ImageVulnerabilitySummary.MaxSeverity == nil {
 			break
@@ -549,6 +583,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.ImageVulnerabilitySummary.MaxSeverity(childComplexity), true
 
+	case "ImageVulnerabilitySummary.MediumCount":
+		if e.complexity.ImageVulnerabilitySummary.MediumCount == nil {
+			break
+		}
+
+		return e.complexity.ImageVulnerabilitySummary.MediumCount(childComplexity), true
+
+	case "ImageVulnerabilitySummary.UnknownCount":
+		if e.complexity.ImageVulnerabilitySummary.UnknownCount == nil {
+			break
+		}
+
+		return e.complexity.ImageVulnerabilitySummary.UnknownCount(childComplexity), true
+
 	case "LayerHistory.HistoryDescription":
 		if e.complexity.LayerHistory.HistoryDescription == nil {
 			break
@@ -1164,6 +1212,7 @@ A timestamp
 """
 scalar Time
 
+
 """
 Contains the tag of the image and a list of CVEs
 """
@@ -1177,6 +1226,10 @@ type CVEResultForImage {
     """
     CVEList: [CVE]
     """
+    Summary of the findings for this image
+    """
+    Summary: ImageVulnerabilitySummary
+    """
     The CVE pagination information, see PageInfo object for more details
     """
     Page: PageInfo
@@ -1430,6 +1483,26 @@ type ImageVulnerabilitySummary {
     Count of all CVEs found in this image
     """
     Count: Int
+    """
+    Coresponds to CVSS 3 score NONE
+    """
+    UnknownCount: Int
+    """
+    Coresponds to CVSS 3 score LOW
+    """
+    LowCount: Int
+    """
+    Coresponds to CVSS 3 score MEDIUM
+    """
+    MediumCount: Int
+    """
+    Coresponds to CVSS 3 score HIGH
+    """
+    HighCount: Int
+    """
+    Coresponds to CVSS 3 score CRITICAL
+    """
+    CriticalCount: Int
 }
 
 """
@@ -2761,6 +2834,63 @@ func (ec *executionContext) fieldContext_CVEResultForImage_CVEList(ctx context.C
 	return fc, nil
 }
 
+func (ec *executionContext) _CVEResultForImage_Summary(ctx context.Context, field graphql.CollectedField, obj *CVEResultForImage) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_CVEResultForImage_Summary(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.Summary, nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*ImageVulnerabilitySummary)
+	fc.Result = res
+	return ec.marshalOImageVulnerabilitySummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageVulnerabilitySummary(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_CVEResultForImage_Summary(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "CVEResultForImage",
+		Field:      field,
+		IsMethod:   false,
+		IsResolver: false,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			switch field.Name {
+			case "MaxSeverity":
+				return ec.fieldContext_ImageVulnerabilitySummary_MaxSeverity(ctx, field)
+			case "Count":
+				return ec.fieldContext_ImageVulnerabilitySummary_Count(ctx, field)
+			case "UnknownCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_UnknownCount(ctx, field)
+			case "LowCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_LowCount(ctx, field)
+			case "MediumCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_MediumCount(ctx, field)
+			case "HighCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_HighCount(ctx, field)
+			case "CriticalCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_CriticalCount(ctx, field)
+			}
+			return nil, fmt.Errorf("no field named %q was found under type ImageVulnerabilitySummary", field.Name)
+		},
+	}
+	return fc, nil
+}
+
 func (ec *executionContext) _CVEResultForImage_Page(ctx context.Context, field graphql.CollectedField, obj *CVEResultForImage) (ret graphql.Marshaler) {
 	fc, err := ec.fieldContext_CVEResultForImage_Page(ctx, field)
 	if err != nil {
@@ -4071,6 +4201,16 @@ func (ec *executionContext) fieldContext_ImageSummary_Vulnerabilities(ctx contex
 				return ec.fieldContext_ImageVulnerabilitySummary_MaxSeverity(ctx, field)
 			case "Count":
 				return ec.fieldContext_ImageVulnerabilitySummary_Count(ctx, field)
+			case "UnknownCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_UnknownCount(ctx, field)
+			case "LowCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_LowCount(ctx, field)
+			case "MediumCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_MediumCount(ctx, field)
+			case "HighCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_HighCount(ctx, field)
+			case "CriticalCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_CriticalCount(ctx, field)
 			}
 			return nil, fmt.Errorf("no field named %q was found under type ImageVulnerabilitySummary", field.Name)
 		},
@@ -4254,6 +4394,211 @@ func (ec *executionContext) fieldContext_ImageVulnerabilitySummary_Count(ctx con
 	return fc, nil
 }
 
+func (ec *executionContext) _ImageVulnerabilitySummary_UnknownCount(ctx context.Context, field graphql.CollectedField, obj *ImageVulnerabilitySummary) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_ImageVulnerabilitySummary_UnknownCount(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.UnknownCount, nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*int)
+	fc.Result = res
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_ImageVulnerabilitySummary_UnknownCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "ImageVulnerabilitySummary",
+		Field:      field,
+		IsMethod:   false,
+		IsResolver: false,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type Int does not have child fields")
+		},
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _ImageVulnerabilitySummary_LowCount(ctx context.Context, field graphql.CollectedField, obj *ImageVulnerabilitySummary) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_ImageVulnerabilitySummary_LowCount(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.LowCount, nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*int)
+	fc.Result = res
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_ImageVulnerabilitySummary_LowCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "ImageVulnerabilitySummary",
+		Field:      field,
+		IsMethod:   false,
+		IsResolver: false,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type Int does not have child fields")
+		},
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _ImageVulnerabilitySummary_MediumCount(ctx context.Context, field graphql.CollectedField, obj *ImageVulnerabilitySummary) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_ImageVulnerabilitySummary_MediumCount(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.MediumCount, nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*int)
+	fc.Result = res
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_ImageVulnerabilitySummary_MediumCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "ImageVulnerabilitySummary",
+		Field:      field,
+		IsMethod:   false,
+		IsResolver: false,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type Int does not have child fields")
+		},
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _ImageVulnerabilitySummary_HighCount(ctx context.Context, field graphql.CollectedField, obj *ImageVulnerabilitySummary) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_ImageVulnerabilitySummary_HighCount(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.HighCount, nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*int)
+	fc.Result = res
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_ImageVulnerabilitySummary_HighCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "ImageVulnerabilitySummary",
+		Field:      field,
+		IsMethod:   false,
+		IsResolver: false,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type Int does not have child fields")
+		},
+	}
+	return fc, nil
+}
+
+func (ec *executionContext) _ImageVulnerabilitySummary_CriticalCount(ctx context.Context, field graphql.CollectedField, obj *ImageVulnerabilitySummary) (ret graphql.Marshaler) {
+	fc, err := ec.fieldContext_ImageVulnerabilitySummary_CriticalCount(ctx, field)
+	if err != nil {
+		return graphql.Null
+	}
+	ctx = graphql.WithFieldContext(ctx, fc)
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.CriticalCount, nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*int)
+	fc.Result = res
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_ImageVulnerabilitySummary_CriticalCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+	fc = &graphql.FieldContext{
+		Object:     "ImageVulnerabilitySummary",
+		Field:      field,
+		IsMethod:   false,
+		IsResolver: false,
+		Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+			return nil, errors.New("field of type Int does not have child fields")
+		},
+	}
+	return fc, nil
+}
+
 func (ec *executionContext) _LayerHistory_Layer(ctx context.Context, field graphql.CollectedField, obj *LayerHistory) (ret graphql.Marshaler) {
 	fc, err := ec.fieldContext_LayerHistory_Layer(ctx, field)
 	if err != nil {
@@ -4912,6 +5257,16 @@ func (ec *executionContext) fieldContext_ManifestSummary_Vulnerabilities(ctx con
 				return ec.fieldContext_ImageVulnerabilitySummary_MaxSeverity(ctx, field)
 			case "Count":
 				return ec.fieldContext_ImageVulnerabilitySummary_Count(ctx, field)
+			case "UnknownCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_UnknownCount(ctx, field)
+			case "LowCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_LowCount(ctx, field)
+			case "MediumCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_MediumCount(ctx, field)
+			case "HighCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_HighCount(ctx, field)
+			case "CriticalCount":
+				return ec.fieldContext_ImageVulnerabilitySummary_CriticalCount(ctx, field)
 			}
 			return nil, fmt.Errorf("no field named %q was found under type ImageVulnerabilitySummary", field.Name)
 		},
@@ -5599,6 +5954,8 @@ func (ec *executionContext) fieldContext_Query_CVEListForImage(ctx context.Conte
 				return ec.fieldContext_CVEResultForImage_Tag(ctx, field)
 			case "CVEList":
 				return ec.fieldContext_CVEResultForImage_CVEList(ctx, field)
+			case "Summary":
+				return ec.fieldContext_CVEResultForImage_Summary(ctx, field)
 			case "Page":
 				return ec.fieldContext_CVEResultForImage_Page(ctx, field)
 			}
@@ -9553,6 +9910,8 @@ func (ec *executionContext) _CVEResultForImage(ctx context.Context, sel ast.Sele
 			out.Values[i] = ec._CVEResultForImage_Tag(ctx, field, obj)
 		case "CVEList":
 			out.Values[i] = ec._CVEResultForImage_CVEList(ctx, field, obj)
+		case "Summary":
+			out.Values[i] = ec._CVEResultForImage_Summary(ctx, field, obj)
 		case "Page":
 			out.Values[i] = ec._CVEResultForImage_Page(ctx, field, obj)
 		default:
@@ -9755,6 +10114,16 @@ func (ec *executionContext) _ImageVulnerabilitySummary(ctx context.Context, sel
 			out.Values[i] = ec._ImageVulnerabilitySummary_MaxSeverity(ctx, field, obj)
 		case "Count":
 			out.Values[i] = ec._ImageVulnerabilitySummary_Count(ctx, field, obj)
+		case "UnknownCount":
+			out.Values[i] = ec._ImageVulnerabilitySummary_UnknownCount(ctx, field, obj)
+		case "LowCount":
+			out.Values[i] = ec._ImageVulnerabilitySummary_LowCount(ctx, field, obj)
+		case "MediumCount":
+			out.Values[i] = ec._ImageVulnerabilitySummary_MediumCount(ctx, field, obj)
+		case "HighCount":
+			out.Values[i] = ec._ImageVulnerabilitySummary_HighCount(ctx, field, obj)
+		case "CriticalCount":
+			out.Values[i] = ec._ImageVulnerabilitySummary_CriticalCount(ctx, field, obj)
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
diff --git a/pkg/extensions/search/gql_generated/models_gen.go b/pkg/extensions/search/gql_generated/models_gen.go
index 9e654c536..00a82c757 100644
--- a/pkg/extensions/search/gql_generated/models_gen.go
+++ b/pkg/extensions/search/gql_generated/models_gen.go
@@ -41,6 +41,8 @@ type CVEResultForImage struct {
 	Tag *string `json:"Tag,omitempty"`
 	// List of CVE objects which affect this specific image:tag
 	CVEList []*Cve `json:"CVEList,omitempty"`
+	// Summary of the findings for this image
+	Summary *ImageVulnerabilitySummary `json:"Summary,omitempty"`
 	// The CVE pagination information, see PageInfo object for more details
 	Page *PageInfo `json:"Page,omitempty"`
 }
@@ -144,6 +146,16 @@ type ImageVulnerabilitySummary struct {
 	MaxSeverity *string `json:"MaxSeverity,omitempty"`
 	// Count of all CVEs found in this image
 	Count *int `json:"Count,omitempty"`
+	// Coresponds to CVSS 3 score NONE
+	UnknownCount *int `json:"UnknownCount,omitempty"`
+	// Coresponds to CVSS 3 score LOW
+	LowCount *int `json:"LowCount,omitempty"`
+	// Coresponds to CVSS 3 score MEDIUM
+	MediumCount *int `json:"MediumCount,omitempty"`
+	// Coresponds to CVSS 3 score HIGH
+	HighCount *int `json:"HighCount,omitempty"`
+	// Coresponds to CVSS 3 score CRITICAL
+	CriticalCount *int `json:"CriticalCount,omitempty"`
 }
 
 // Information about how/when a layer was built
diff --git a/pkg/extensions/search/resolver.go b/pkg/extensions/search/resolver.go
index 86309b55e..220663f35 100644
--- a/pkg/extensions/search/resolver.go
+++ b/pkg/extensions/search/resolver.go
@@ -216,7 +216,8 @@ func getCVEListForImage(
 		return &gql_generated.CVEResultForImage{}, gqlerror.Errorf("no reference provided")
 	}
 
-	cveList, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo, ref, searchedCVE, pageInput)
+	cveList, imageCveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo, ref,
+		searchedCVE, pageInput)
 	if err != nil {
 		return &gql_generated.CVEResultForImage{}, err
 	}
@@ -259,6 +260,15 @@ func getCVEListForImage(
 	return &gql_generated.CVEResultForImage{
 		Tag:     &ref,
 		CVEList: cveids,
+		Summary: &gql_generated.ImageVulnerabilitySummary{
+			MaxSeverity:   &imageCveSummary.MaxSeverity,
+			UnknownCount:  &imageCveSummary.UnknownCount,
+			LowCount:      &imageCveSummary.LowCount,
+			MediumCount:   &imageCveSummary.MediumCount,
+			HighCount:     &imageCveSummary.HighCount,
+			CriticalCount: &imageCveSummary.CriticalCount,
+			Count:         &imageCveSummary.Count,
+		},
 		Page: &gql_generated.PageInfo{
 			TotalCount: pageInfo.TotalCount,
 			ItemCount:  pageInfo.ItemCount,
diff --git a/pkg/extensions/search/schema.graphql b/pkg/extensions/search/schema.graphql
index c1b50453f..9f7f19c0f 100644
--- a/pkg/extensions/search/schema.graphql
+++ b/pkg/extensions/search/schema.graphql
@@ -10,6 +10,7 @@ A timestamp
 """
 scalar Time
 
+
 """
 Contains the tag of the image and a list of CVEs
 """
@@ -23,6 +24,10 @@ type CVEResultForImage {
     """
     CVEList: [CVE]
     """
+    Summary of the findings for this image
+    """
+    Summary: ImageVulnerabilitySummary
+    """
     The CVE pagination information, see PageInfo object for more details
     """
     Page: PageInfo
@@ -276,6 +281,26 @@ type ImageVulnerabilitySummary {
     Count of all CVEs found in this image
     """
     Count: Int
+    """
+    Coresponds to CVSS 3 score NONE
+    """
+    UnknownCount: Int
+    """
+    Coresponds to CVSS 3 score LOW
+    """
+    LowCount: Int
+    """
+    Coresponds to CVSS 3 score MEDIUM
+    """
+    MediumCount: Int
+    """
+    Coresponds to CVSS 3 score HIGH
+    """
+    HighCount: Int
+    """
+    Coresponds to CVSS 3 score CRITICAL
+    """
+    CriticalCount: Int
 }
 
 """
diff --git a/pkg/extensions/search/search_test.go b/pkg/extensions/search/search_test.go
index b13dd8934..6a4634bc9 100644
--- a/pkg/extensions/search/search_test.go
+++ b/pkg/extensions/search/search_test.go
@@ -18,7 +18,6 @@ import (
 	"testing"
 	"time"
 
-	dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
 	guuid "github.com/gofrs/uuid"
 	regTypes "github.com/google/go-containerregistry/pkg/v1/types"
 	notreg "github.com/notaryproject/notation-go/registry"
@@ -530,6 +529,11 @@ func TestRepoListWithNewestImage(t *testing.T) {
 							Tag
 							Vulnerabilities{
 								MaxSeverity
+								UnknownCount
+								LowCount
+								MediumCount
+								HighCount
+								CriticalCount
 								Count
 							}
 						}
@@ -551,6 +555,11 @@ func TestRepoListWithNewestImage(t *testing.T) {
 			images = responseStruct.Results
 			So(images[0].NewestImage.Tag, ShouldEqual, "0.0.1")
 			So(images[0].NewestImage.Vulnerabilities.Count, ShouldEqual, 0)
+			So(images[0].NewestImage.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+			So(images[0].NewestImage.Vulnerabilities.LowCount, ShouldEqual, 0)
+			So(images[0].NewestImage.Vulnerabilities.MediumCount, ShouldEqual, 0)
+			So(images[0].NewestImage.Vulnerabilities.HighCount, ShouldEqual, 0)
+			So(images[0].NewestImage.Vulnerabilities.CriticalCount, ShouldEqual, 0)
 			So(images[0].NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "")
 
 			query = `{
@@ -741,6 +750,11 @@ func TestRepoListWithNewestImage(t *testing.T) {
 						Digest
 						Vulnerabilities{
 							MaxSeverity
+							UnknownCount
+							LowCount
+							MediumCount
+							HighCount
+							CriticalCount
 							Count
 						}
 					}
@@ -765,12 +779,12 @@ func TestRepoListWithNewestImage(t *testing.T) {
 			So(vulnerabilities, ShouldNotBeNil)
 			t.Logf("Found vulnerability summary %v", vulnerabilities)
 			// Depends on test data, but current tested images contain hundreds
-			So(vulnerabilities.Count, ShouldBeGreaterThan, 1)
-			So(
-				dbTypes.CompareSeverityString(dbTypes.SeverityUnknown.String(), vulnerabilities.MaxSeverity),
-				ShouldBeGreaterThan,
-				0,
-			)
+			So(vulnerabilities.Count, ShouldEqual, 4)
+			So(vulnerabilities.UnknownCount, ShouldEqual, 0)
+			So(vulnerabilities.LowCount, ShouldEqual, 1)
+			So(vulnerabilities.MediumCount, ShouldEqual, 1)
+			So(vulnerabilities.HighCount, ShouldEqual, 1)
+			So(vulnerabilities.CriticalCount, ShouldEqual, 1)
 			So(vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
 		}
 	})
@@ -3178,7 +3192,7 @@ func TestGlobalSearch(t *testing.T) {
 								Layer { Size Digest }
 								HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 							}
-							Vulnerabilities { Count MaxSeverity }
+							Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 						}
 						Vendor
 						Vulnerabilities { Count MaxSeverity }
@@ -3199,7 +3213,7 @@ func TestGlobalSearch(t *testing.T) {
 									HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 								}
 							}
-							Vulnerabilities { Count MaxSeverity }
+							Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 						}
 					}
 					Layers { Digest Size }
@@ -3256,6 +3270,11 @@ func TestGlobalSearch(t *testing.T) {
 			// No vulnerabilities should be detected since trivy is disabled
 			t.Logf("Found vulnerability summary %v", repoSummary.NewestImage.Vulnerabilities)
 			So(repoSummary.NewestImage.Vulnerabilities.Count, ShouldEqual, 0)
+			So(repoSummary.NewestImage.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+			So(repoSummary.NewestImage.Vulnerabilities.LowCount, ShouldEqual, 0)
+			So(repoSummary.NewestImage.Vulnerabilities.MediumCount, ShouldEqual, 0)
+			So(repoSummary.NewestImage.Vulnerabilities.HighCount, ShouldEqual, 0)
+			So(repoSummary.NewestImage.Vulnerabilities.CriticalCount, ShouldEqual, 0)
 			So(repoSummary.NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "")
 		}
 
@@ -3272,7 +3291,7 @@ func TestGlobalSearch(t *testing.T) {
 							HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 						}
 					}
-					Vulnerabilities { Count MaxSeverity }
+					Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 				}
 				Repos {
 					Name LastUpdated Size
@@ -3288,7 +3307,7 @@ func TestGlobalSearch(t *testing.T) {
 								HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 							}
 						}
-						Vulnerabilities { Count MaxSeverity }
+						Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 					}
 				}
 				Layers { Digest Size }
@@ -3323,6 +3342,11 @@ func TestGlobalSearch(t *testing.T) {
 		// 0 vulnerabilities should be detected since trivy is disabled
 		t.Logf("Found vulnerability summary %v", actualImageSummary.Vulnerabilities)
 		So(actualImageSummary.Vulnerabilities.Count, ShouldEqual, 0)
+		So(actualImageSummary.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+		So(actualImageSummary.Vulnerabilities.LowCount, ShouldEqual, 0)
+		So(actualImageSummary.Vulnerabilities.MediumCount, ShouldEqual, 0)
+		So(actualImageSummary.Vulnerabilities.HighCount, ShouldEqual, 0)
+		So(actualImageSummary.Vulnerabilities.CriticalCount, ShouldEqual, 0)
 		So(actualImageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
 	})
 
@@ -3500,7 +3524,7 @@ func TestGlobalSearch(t *testing.T) {
 								HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 							}
 						}
-						Vulnerabilities { Count MaxSeverity }
+						Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 					}
 					Repos {
 						Name LastUpdated Size
@@ -3516,7 +3540,7 @@ func TestGlobalSearch(t *testing.T) {
 									HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 								}
 							}
-							Vulnerabilities { Count MaxSeverity }
+							Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 						}
 					}
 					Layers { Digest Size }
@@ -3575,10 +3599,20 @@ func TestGlobalSearch(t *testing.T) {
 			if repoName == "repo1" { //nolint:goconst
 				So(repoSummary.NewestImage.Vulnerabilities.Count, ShouldEqual, 4)
 				// There are 4 vulnerabilities in the data used in tests
+				So(repoSummary.NewestImage.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+				So(repoSummary.NewestImage.Vulnerabilities.LowCount, ShouldEqual, 1)
+				So(repoSummary.NewestImage.Vulnerabilities.MediumCount, ShouldEqual, 1)
+				So(repoSummary.NewestImage.Vulnerabilities.HighCount, ShouldEqual, 1)
+				So(repoSummary.NewestImage.Vulnerabilities.CriticalCount, ShouldEqual, 1)
 				So(repoSummary.NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
 			} else {
 				So(repoSummary.NewestImage.Vulnerabilities.Count, ShouldEqual, 0)
 				// There are 0 vulnerabilities this data used in tests
+				So(repoSummary.NewestImage.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+				So(repoSummary.NewestImage.Vulnerabilities.LowCount, ShouldEqual, 0)
+				So(repoSummary.NewestImage.Vulnerabilities.MediumCount, ShouldEqual, 0)
+				So(repoSummary.NewestImage.Vulnerabilities.HighCount, ShouldEqual, 0)
+				So(repoSummary.NewestImage.Vulnerabilities.CriticalCount, ShouldEqual, 0)
 				So(repoSummary.NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "NONE")
 			}
 		}
@@ -3596,7 +3630,7 @@ func TestGlobalSearch(t *testing.T) {
 							HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 						}
 					}
-					Vulnerabilities { Count MaxSeverity }
+					Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount  MaxSeverity }
 				}
 				Repos {
 					Name LastUpdated Size
@@ -3612,7 +3646,7 @@ func TestGlobalSearch(t *testing.T) {
 								HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 							}
 						}
-						Vulnerabilities { Count MaxSeverity }
+						Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 					}
 				}
 				Layers { Digest Size }
@@ -3647,6 +3681,11 @@ func TestGlobalSearch(t *testing.T) {
 		t.Logf("Found vulnerability summary %v", actualImageSummary.Vulnerabilities)
 		// There are 4 vulnerabilities in the data used in tests
 		So(actualImageSummary.Vulnerabilities.Count, ShouldEqual, 4)
+		So(actualImageSummary.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+		So(actualImageSummary.Vulnerabilities.LowCount, ShouldEqual, 1)
+		So(actualImageSummary.Vulnerabilities.MediumCount, ShouldEqual, 1)
+		So(actualImageSummary.Vulnerabilities.HighCount, ShouldEqual, 1)
+		So(actualImageSummary.Vulnerabilities.CriticalCount, ShouldEqual, 1)
 		So(actualImageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
 	})
 
@@ -5949,7 +5988,7 @@ func TestImageSummary(t *testing.T) {
 						Size
 						Platform { Os Arch }
 						Layers { Digest Size }
-						Vulnerabilities { Count MaxSeverity }
+						Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 						History {
 							HistoryDescription { Created }
 							Layer { Digest Size }
@@ -5957,7 +5996,7 @@ func TestImageSummary(t *testing.T) {
 					}
 					LastUpdated
 					Size
-					Vulnerabilities { Count MaxSeverity }
+					Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 					Referrers {MediaType ArtifactType Digest Annotations {Key Value}}
 				}
 			}`
@@ -5976,7 +6015,7 @@ func TestImageSummary(t *testing.T) {
 						Size
 						Platform { Os Arch }
 						Layers { Digest Size }
-						Vulnerabilities { Count MaxSeverity }
+						Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 						History {
 							HistoryDescription { Created }
 							Layer { Digest Size }
@@ -6089,6 +6128,11 @@ func TestImageSummary(t *testing.T) {
 		So(imgSummary.Manifests[0].History[0].HistoryDescription.Created, ShouldEqual, createdTime)
 		// No vulnerabilities should be detected since trivy is disabled
 		So(imgSummary.Vulnerabilities.Count, ShouldEqual, 0)
+		So(imgSummary.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+		So(imgSummary.Vulnerabilities.LowCount, ShouldEqual, 0)
+		So(imgSummary.Vulnerabilities.MediumCount, ShouldEqual, 0)
+		So(imgSummary.Vulnerabilities.HighCount, ShouldEqual, 0)
+		So(imgSummary.Vulnerabilities.CriticalCount, ShouldEqual, 0)
 		So(imgSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
 		So(len(imgSummary.Referrers), ShouldEqual, 1)
 		So(imgSummary.Referrers[0], ShouldResemble, zcommon.Referrer{
@@ -6177,7 +6221,7 @@ func TestImageSummary(t *testing.T) {
 						Size
 						Platform { Os Arch }
 						Layers { Digest Size }
-						Vulnerabilities { Count MaxSeverity }
+						Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 						History {
 							HistoryDescription { Created }
 							Layer { Digest Size }
@@ -6185,7 +6229,7 @@ func TestImageSummary(t *testing.T) {
 					}
 					LastUpdated
 					Size
-					Vulnerabilities { Count MaxSeverity }
+					Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 				}
 			}`
 
@@ -6271,6 +6315,11 @@ func TestImageSummary(t *testing.T) {
 		So(len(imgSummary.Manifests[0].History), ShouldEqual, 1)
 		So(imgSummary.Manifests[0].History[0].HistoryDescription.Created, ShouldEqual, createdTime)
 		So(imgSummary.Vulnerabilities.Count, ShouldEqual, 4)
+		So(imgSummary.Vulnerabilities.UnknownCount, ShouldEqual, 0)
+		So(imgSummary.Vulnerabilities.LowCount, ShouldEqual, 1)
+		So(imgSummary.Vulnerabilities.MediumCount, ShouldEqual, 1)
+		So(imgSummary.Vulnerabilities.HighCount, ShouldEqual, 1)
+		So(imgSummary.Vulnerabilities.CriticalCount, ShouldEqual, 1)
 		// There are 0 vulnerabilities this data used in tests
 		So(imgSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
 	})
@@ -6800,11 +6849,11 @@ func GlobalSearchGQL(query, baseURL string) *zcommon.GlobalSearchResultResp {
 						Layer { Size Digest }
 						HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 					}
-					Vulnerabilities {Count MaxSeverity}
+					Vulnerabilities {Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity}
 					Referrers {MediaType ArtifactType Size Digest Annotations {Key Value}}
 				}
 				Referrers {MediaType ArtifactType Size Digest Annotations {Key Value}}
-				Vulnerabilities { Count MaxSeverity }
+				Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 				SignatureInfo {Tool IsTrusted Author}
 			}
 			Repos {
@@ -6824,11 +6873,11 @@ func GlobalSearchGQL(query, baseURL string) *zcommon.GlobalSearchResultResp {
 							Layer { Size Digest }
 							HistoryDescription { Author Comment Created CreatedBy EmptyLayer }
 						}
-						Vulnerabilities {Count MaxSeverity}
+						Vulnerabilities {Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity}
 						Referrers {MediaType ArtifactType Size Digest Annotations {Key Value}}
 					}
 					Referrers {MediaType ArtifactType Size Digest Annotations {Key Value}}
-					Vulnerabilities { Count MaxSeverity }
+					Vulnerabilities { Count UnknownCount LowCount MediumCount HighCount CriticalCount MaxSeverity }
 					SignatureInfo {Tool IsTrusted Author}
 				}
 			}
diff --git a/pkg/test/mocks/cve_mock.go b/pkg/test/mocks/cve_mock.go
index 03d17a0b9..ad11abf59 100644
--- a/pkg/test/mocks/cve_mock.go
+++ b/pkg/test/mocks/cve_mock.go
@@ -11,7 +11,7 @@ type CveInfoMock struct {
 	GetImageListForCVEFn       func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
 	GetImageListWithCVEFixedFn func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
 	GetCVEListForImageFn       func(ctx context.Context, repo string, reference string, searchedCVE string,
-		pageInput cvemodel.PageInput) ([]cvemodel.CVE, common.PageInfo, error)
+		pageInput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, common.PageInfo, error)
 	GetCVESummaryForImageMediaFn func(ctx context.Context, repo string, digest, mediaType string,
 	) (cvemodel.ImageCVESummary, error)
 }
@@ -37,6 +37,7 @@ func (cveInfo CveInfoMock) GetCVEListForImage(ctx context.Context, repo string,
 	searchedCVE string, pageInput cvemodel.PageInput,
 ) (
 	[]cvemodel.CVE,
+	cvemodel.ImageCVESummary,
 	common.PageInfo,
 	error,
 ) {
@@ -44,7 +45,7 @@ func (cveInfo CveInfoMock) GetCVEListForImage(ctx context.Context, repo string,
 		return cveInfo.GetCVEListForImageFn(ctx, repo, reference, searchedCVE, pageInput)
 	}
 
-	return []cvemodel.CVE{}, common.PageInfo{}, nil
+	return []cvemodel.CVE{}, cvemodel.ImageCVESummary{}, common.PageInfo{}, nil
 }
 
 func (cveInfo CveInfoMock) GetCVESummaryForImageMedia(ctx context.Context, repo, digest, mediaType string,