diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
index 69733973e7cc1ca423744b42411d5c0e6d3c375e..2c6f1da367f5e7848099cc3a9ff94c6980d49203 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
@@ -22,6 +22,10 @@ export default {
       import(
         'ee_component/packages_and_registries/container_registry/explorer/components/list_page/metadata_container_scanning.vue'
       ),
+    ContainerScanningCounts: () =>
+      import(
+        'ee_component/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts.vue'
+      ),
   },
   inject: ['config'],
   props: {
@@ -123,5 +127,9 @@ export default {
     <template v-if="!config.isGroupPage" #metadata-container-scanning>
       <metadata-container-scanning />
     </template>
+
+    <template v-if="!config.isGroupPage">
+      <container-scanning-counts />
+    </template>
   </title-area>
 </template>
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js
index 1e22469edd19dd88c6ebd66613717d29a158ac3e..dacc621bed7b2361e40cfefb8135e5f66284008c 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js
@@ -43,6 +43,7 @@ export default () => {
     invalidPathError,
     securityConfigurationPath,
     containerScanningForRegistryDocsPath,
+    vulnerabilityReportPath,
     ...config
   } = el.dataset;
 
@@ -80,6 +81,7 @@ export default () => {
             isMetadataDatabaseEnabled: parseBoolean(isMetadataDatabaseEnabled),
             securityConfigurationPath,
             containerScanningForRegistryDocsPath,
+            vulnerabilityReportPath,
           },
           /* eslint-disable @gitlab/require-i18n-strings */
           dockerBuildCommand: `docker build -t ${config.repositoryUrl} .`,
diff --git a/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts.vue b/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7cda9aff4b0f90fac5346bde02492455494974d8
--- /dev/null
+++ b/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts.vue
@@ -0,0 +1,133 @@
+<script>
+import { GlSkeletonLoader, GlSprintf, GlIcon, GlLink } from '@gitlab/ui';
+import countsQuery from 'ee/packages_and_registries/container_registry/explorer/graphql/queries/get_project_container_scanning.query.graphql';
+import { REPORT_TYPE_PRESETS } from 'ee/security_dashboard/components/shared/vulnerability_report/constants';
+import {
+  VULNERABILITY_STATE_OBJECTS,
+  CRITICAL,
+  HIGH,
+  MEDIUM,
+  LOW,
+  INFO,
+  UNKNOWN,
+  SEVERITY_COUNT_LIMIT,
+  SEVERITIES,
+} from 'ee/vulnerabilities/constants';
+import { s__, sprintf } from '~/locale';
+import * as Sentry from '~/sentry/sentry_browser_wrapper';
+
+const { detected, confirmed } = VULNERABILITY_STATE_OBJECTS;
+
+export default {
+  components: { GlSkeletonLoader, GlSprintf, GlIcon, GlLink },
+  inject: ['config'],
+  data() {
+    return {
+      project: {},
+    };
+  },
+  i18n: {
+    highlights: s__(
+      'ciReport|%{criticalStart}critical%{criticalEnd}, %{highStart}high%{highEnd} and %{otherStart}other%{otherEnd} vulnerabilities detected.',
+    ),
+    latestTagsOnly: s__('ciReport|Runs against latest tags only'),
+    viewVulnerabilities: s__('ciReport|View vulnerabilities'),
+  },
+  computed: {
+    isEnabled() {
+      return (
+        this.project?.containerScanningForRegistry.isEnabled &&
+        this.project?.containerScanningForRegistry.isVisible
+      );
+    },
+    isLoadingCounts() {
+      return this.$apollo.queries.project.loading;
+    },
+    severityCounts() {
+      return SEVERITIES.map((severity) => ({
+        severity,
+        count: this.counts[severity] || 0,
+      }));
+    },
+    counts() {
+      return this.project?.vulnerabilitySeveritiesCount || {};
+    },
+    criticalSeverity() {
+      return this.formattedCounts(this.counts[CRITICAL]);
+    },
+    highSeverity() {
+      return this.formattedCounts(this.counts[HIGH]);
+    },
+    otherSeverity() {
+      let totalCounts = 0;
+
+      [MEDIUM, LOW, INFO, UNKNOWN].forEach((severity) => {
+        const count = this.counts[severity];
+
+        if (count) {
+          totalCounts += count;
+        }
+      });
+
+      return this.formattedCounts(totalCounts);
+    },
+  },
+  apollo: {
+    project: {
+      query: countsQuery,
+      errorPolicy: 'none',
+      variables() {
+        return {
+          fullPath: this.config.projectPath,
+          securityConfigurationPath: this.config.securityConfigurationPath,
+          reportType: REPORT_TYPE_PRESETS.CONTAINER_REGISTRY,
+          state: [detected.searchParamValue, confirmed.searchParamValue],
+          capped: true,
+        };
+      },
+      update(data) {
+        return data.project;
+      },
+      error(e) {
+        Sentry.captureException(e);
+      },
+    },
+  },
+  methods: {
+    formattedCounts(count) {
+      return count > SEVERITY_COUNT_LIMIT
+        ? sprintf(s__('SecurityReports|%{count}+'), { count: SEVERITY_COUNT_LIMIT })
+        : count;
+    },
+  },
+};
+</script>
+
+<template>
+  <div>
+    <gl-skeleton-loader v-if="isLoadingCounts" :equal-width-lines="true" :lines="3" />
+    <div v-else-if="isEnabled" class="gl-border gl-my-6 gl-p-5 gl-text-base">
+      <div data-testid="counts">
+        <gl-sprintf :message="$options.i18n.highlights">
+          <template #critical="{ content }"
+            ><strong class="gl-text-red-800">{{ criticalSeverity }} {{ content }}</strong></template
+          >
+          <template #high="{ content }"
+            ><strong class="gl-text-red-600">{{ highSeverity }} {{ content }}</strong></template
+          >
+          <template #other="{ content }"
+            ><strong>{{ otherSeverity }} {{ content }}</strong></template
+          >
+        </gl-sprintf>
+        <gl-link :href="config.vulnerabilityReportPath">{{
+          $options.i18n.viewVulnerabilities
+        }}</gl-link>
+      </div>
+
+      <div class="gl-pt-2 gl-text-secondary">
+        <gl-icon name="information-o" />
+        {{ $options.i18n.latestTagsOnly }}
+      </div>
+    </div>
+  </div>
+</template>
diff --git a/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/metadata_container_scanning.vue b/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/metadata_container_scanning.vue
index 0c3d47f7e7d4f390f4fd93c433d059e11c02f96d..3532a2d15bf57758a4e9795887a959ee5b10afb4 100644
--- a/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/metadata_container_scanning.vue
+++ b/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/metadata_container_scanning.vue
@@ -1,9 +1,12 @@
 <script>
 import { GlSkeletonLoader, GlIcon, GlPopover, GlLink } from '@gitlab/ui';
 import { s__ } from '~/locale';
-import { fetchPolicies } from '~/lib/graphql';
+import { REPORT_TYPE_PRESETS } from 'ee/security_dashboard/components/shared/vulnerability_report/constants';
+import { VULNERABILITY_STATE_OBJECTS } from 'ee/vulnerabilities/constants';
 import getProjectContainerScanning from '../../graphql/queries/get_project_container_scanning.query.graphql';
 
+const { detected, confirmed } = VULNERABILITY_STATE_OBJECTS;
+
 export default {
   components: {
     GlIcon,
@@ -20,14 +23,17 @@ export default {
         return {
           fullPath: this.config.projectPath,
           securityConfigurationPath: this.config.securityConfigurationPath,
+          reportType: REPORT_TYPE_PRESETS.CONTAINER_REGISTRY,
+          state: [detected.searchParamValue, confirmed.searchParamValue],
         };
       },
-      // We need this for handling loading state when using frontend cache
-      // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106004#note_1217325202 for details
-      fetchPolicy: fetchPolicies.CACHE_ONLY,
-      notifyOnNetworkStatusChange: true,
       update(data) {
-        return data.project.containerScanningForRegistry ?? { isEnabled: false, isVisible: false };
+        return (
+          data.project.containerScanningForRegistry ?? {
+            isEnabled: false,
+            isVisible: false,
+          }
+        );
       },
     },
   },
diff --git a/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_project_container_scanning.query.graphql b/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_project_container_scanning.query.graphql
index ea4ebff1737ddd9b9013a744c1a95527cf223d8b..4d739d144a7926d10e8366ccb500c8ec5883ec22 100644
--- a/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_project_container_scanning.query.graphql
+++ b/ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_project_container_scanning.query.graphql
@@ -1,9 +1,20 @@
-query getProjectContainerScanning($fullPath: ID!, $securityConfigurationPath: String!) {
+#import "ee/security_dashboard/graphql/fragments/vulnerability_severities_count.fragment.graphql"
+
+query getProjectContainerScanning(
+  $fullPath: ID = ""
+  $securityConfigurationPath: String!
+  $reportType: [VulnerabilityReportType!]
+  $state: [VulnerabilityState!]
+  $capped: Boolean = false
+) {
   project(fullPath: $fullPath) {
     id
     containerScanningForRegistry(securityConfigurationPath: $securityConfigurationPath) @client {
       isEnabled
       isVisible
     }
+    vulnerabilitySeveritiesCount(reportType: $reportType, state: $state, capped: $capped) {
+      ...VulnerabilitySeveritiesCount
+    }
   }
 }
diff --git a/ee/app/helpers/ee/container_registry/container_registry_helper.rb b/ee/app/helpers/ee/container_registry/container_registry_helper.rb
index df5a79ac43bea7091479469ba0508fc196c851d6..7311931723be484f1276167c848b0389ae746e62 100644
--- a/ee/app/helpers/ee/container_registry/container_registry_helper.rb
+++ b/ee/app/helpers/ee/container_registry/container_registry_helper.rb
@@ -9,6 +9,8 @@ module ContainerRegistryHelper
       def project_container_registry_template_data(project, connection_error, invalid_path_error)
         super.merge(
           security_configuration_path: project_security_configuration_path(project),
+          vulnerability_report_path: project_security_vulnerability_report_index_path(project,
+            tab: :CONTAINER_REGISTRY),
           container_scanning_for_registry_docs_path:
             help_page_path('user/application_security/continuous_vulnerability_scanning/index')
         )
diff --git a/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts_spec.js b/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..a069009316e420305bee76e369ff3ab3a3b62c05
--- /dev/null
+++ b/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts_spec.js
@@ -0,0 +1,141 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlSkeletonLoader, GlSprintf, GlLink } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { getProjectContainerScanning } from 'ee/packages_and_registries/container_registry/explorer/graphql/queries/get_project_container_scanning.query.graphql';
+import component from 'ee/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts.vue';
+
+import {
+  graphQLProjectContainerScanningForRegistryOnMock,
+  graphQLProjectContainerScanningForRegistryOnMockCapped,
+  graphQLProjectContainerScanningForRegistryOffMock,
+} from './mock_data';
+
+Vue.use(VueApollo);
+
+describe('Container Scanning Counts', () => {
+  let apolloProvider;
+  let wrapper;
+
+  const findCounts = () => wrapper.findByTestId('counts');
+  const findVulnerabilityReportlink = () => findCounts().findComponent(GlLink);
+  const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+
+  const waitForApolloRequestRender = async () => {
+    await waitForPromises();
+  };
+
+  const mountComponent = ({
+    config = {
+      projectPath: 'project',
+      securityConfigurationPath: '/path',
+      vulnerabilityReportPath: '/vulnerability/report/path',
+    },
+    requestHandlers,
+    containerScanningForRegistryMock,
+  } = {}) => {
+    const cacheOptions = {
+      typePolicies: {
+        Project: {
+          fields: {
+            containerScanningForRegistry: {
+              read() {
+                return containerScanningForRegistryMock;
+              },
+            },
+          },
+        },
+      },
+    };
+
+    apolloProvider = createMockApollo(requestHandlers, {}, cacheOptions);
+
+    apolloProvider.clients.defaultClient.writeQuery({
+      query: getProjectContainerScanning,
+      variables: {
+        fullPath: config.projectPath,
+        securityConfigurationPath: config.securityConfigurationPath,
+        capped: true,
+      },
+      data: graphQLProjectContainerScanningForRegistryOnMock.data,
+    });
+
+    wrapper = shallowMountExtended(component, {
+      apolloProvider,
+      provide() {
+        return {
+          config,
+        };
+      },
+      stubs: {
+        GlSprintf,
+      },
+    });
+  };
+
+  it('renders the counts after skeleton loader', async () => {
+    const requestHandlers = [
+      [
+        getProjectContainerScanning,
+        jest.fn().mockResolvedValue(graphQLProjectContainerScanningForRegistryOnMock),
+      ],
+    ];
+
+    const containerScanningForRegistryMock =
+      graphQLProjectContainerScanningForRegistryOnMock.data.project.containerScanningForRegistry;
+
+    mountComponent({ requestHandlers, containerScanningForRegistryMock });
+
+    expect(findSkeletonLoader().exists()).toBe(true);
+
+    await waitForApolloRequestRender();
+
+    expect(findCounts().text()).toBe(
+      '3 critical, 12 high and 35 other vulnerabilities detected. View vulnerabilities',
+    );
+    expect(findVulnerabilityReportlink().attributes('href')).toBe('/vulnerability/report/path');
+    expect(findSkeletonLoader().exists()).toBe(false);
+  });
+
+  it('renders the counts with capped limit', async () => {
+    const requestHandlers = [
+      [
+        getProjectContainerScanning,
+        jest.fn().mockResolvedValue(graphQLProjectContainerScanningForRegistryOnMockCapped),
+      ],
+    ];
+
+    const containerScanningForRegistryMock =
+      graphQLProjectContainerScanningForRegistryOnMockCapped.data.project
+        .containerScanningForRegistry;
+
+    mountComponent({ requestHandlers, containerScanningForRegistryMock });
+
+    await waitForApolloRequestRender();
+
+    expect(findCounts().text()).toBe(
+      '1000+ critical, 20 high and 1000+ other vulnerabilities detected. View vulnerabilities',
+    );
+    expect(findVulnerabilityReportlink().attributes('href')).toBe('/vulnerability/report/path');
+  });
+
+  it('does not render when disabled', async () => {
+    const requestHandlers = [
+      [
+        getProjectContainerScanning,
+        jest.fn().mockResolvedValue(graphQLProjectContainerScanningForRegistryOffMock),
+      ],
+    ];
+
+    const containerScanningForRegistryMock =
+      graphQLProjectContainerScanningForRegistryOffMock.data.project.containerScanningForRegistry;
+
+    mountComponent({ requestHandlers, containerScanningForRegistryMock });
+
+    await waitForApolloRequestRender();
+
+    expect(findCounts().exists()).toBe(false);
+  });
+});
diff --git a/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/mock_data.js b/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/mock_data.js
index 872b9c16b4c43dbd7a510c5f9747b58c7bc0c5e9..3c667a8b7d94c42dc362d4c4a6304adf754e6133 100644
--- a/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/mock_data.js
+++ b/ee/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/mock_data.js
@@ -7,6 +7,38 @@ export const graphQLProjectContainerScanningForRegistryOnMock = {
         isVisible: true,
         __typename: 'LocalContainerScanningForRegistry',
       },
+      vulnerabilitySeveritiesCount: {
+        critical: 3,
+        high: 12,
+        info: 5,
+        low: 9,
+        medium: 1,
+        unknown: 20,
+        __typename: 'VulnerabilitySeveritiesCount',
+      },
+      __typename: 'Project',
+    },
+  },
+};
+
+export const graphQLProjectContainerScanningForRegistryOnMockCapped = {
+  data: {
+    project: {
+      id: '1',
+      containerScanningForRegistry: {
+        isEnabled: true,
+        isVisible: true,
+        __typename: 'LocalContainerScanningForRegistry',
+      },
+      vulnerabilitySeveritiesCount: {
+        critical: 2000,
+        high: 20,
+        info: 2000,
+        low: 2000,
+        medium: 2000,
+        unknown: 2000,
+        __typename: 'VulnerabilitySeveritiesCount',
+      },
       __typename: 'Project',
     },
   },
@@ -21,6 +53,15 @@ export const graphQLProjectContainerScanningForRegistryOffMock = {
         isVisible: true,
         __typename: 'LocalContainerScanningForRegistry',
       },
+      vulnerabilitySeveritiesCount: {
+        critical: 0,
+        high: 0,
+        info: 0,
+        low: 0,
+        medium: 0,
+        unknown: 0,
+        __typename: 'VulnerabilitySeveritiesCount',
+      },
       __typename: 'Project',
     },
   },
@@ -35,6 +76,15 @@ export const graphQLProjectContainerScanningForRegistryHiddenMock = {
         isVisible: false,
         __typename: 'LocalContainerScanningForRegistry',
       },
+      vulnerabilitySeveritiesCount: {
+        critical: 0,
+        high: 0,
+        info: 0,
+        low: 0,
+        medium: 0,
+        unknown: 0,
+        __typename: 'VulnerabilitySeveritiesCount',
+      },
       __typename: 'Project',
     },
   },
diff --git a/ee/spec/helpers/container_registry/container_registry_helper_spec.rb b/ee/spec/helpers/container_registry/container_registry_helper_spec.rb
index 5eeafd7661d16504241a6f37d6548cdccc0b3be5..9e500a86d9917a731334a8faf5da531501f87414 100644
--- a/ee/spec/helpers/container_registry/container_registry_helper_spec.rb
+++ b/ee/spec/helpers/container_registry/container_registry_helper_spec.rb
@@ -26,6 +26,8 @@
 
       expect(project_container_registry_template_data).to include(
         security_configuration_path: helper.project_security_configuration_path(project),
+        vulnerability_report_path: helper.project_security_vulnerability_report_index_path(project,
+          tab: :CONTAINER_REGISTRY),
         container_scanning_for_registry_docs_path:
           help_page_path('user/application_security/continuous_vulnerability_scanning/index')
       )
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8ca4d2487b069f0c8bf8fce55fd44a125e45b1c3..2b22a96b1837c5e0029bcf474b8c929a63677591 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -64034,6 +64034,9 @@ msgstr[1] ""
 msgid "ci secure files"
 msgstr ""
 
+msgid "ciReport|%{criticalStart}critical%{criticalEnd}, %{highStart}high%{highEnd} and %{otherStart}other%{otherEnd} vulnerabilities detected."
+msgstr ""
+
 msgid "ciReport|%{criticalStart}critical%{criticalEnd}, %{highStart}high%{highEnd} and %{otherStart}others%{otherEnd}"
 msgstr ""
 
@@ -64242,6 +64245,9 @@ msgstr ""
 msgid "ciReport|Resolve with scanner suggestion"
 msgstr ""
 
+msgid "ciReport|Runs against latest tags only"
+msgstr ""
+
 msgid "ciReport|SAST"
 msgstr ""
 
@@ -64307,6 +64313,9 @@ msgstr ""
 msgid "ciReport|View full report"
 msgstr ""
 
+msgid "ciReport|View vulnerabilities"
+msgstr ""
+
 msgid "ciReport|in"
 msgstr ""
 
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
index 47ac3e6bd2a90c0e2938101ae33a1438b3b4a47b..12a11721685df5a8491af479fb4ac690771eed4e 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js
@@ -29,6 +29,7 @@ describe('registry_header', () => {
         GlSprintf,
         TitleArea,
         MetadataContainerScanning: true,
+        ContainerScanningCounts: true,
       },
       propsData,
       slots,
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
index dc5ff35bc6c8ed05784824a9aa07764802c102a2..b6d10cafe5f9aafa01626cd866f975211acdc838 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js
@@ -105,6 +105,7 @@ describe('List Page', () => {
         TitleArea,
         DeleteImage,
         MetadataContainerScanning: true,
+        ContainerScanningCounts: true,
       },
       mocks: {
         $toast,