diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index ec6858892a21fb1c79727b0afbbc297949211e50..46c976d5616ecb18dbd1607d3f5563811655adf3 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -33,6 +33,7 @@ class JobArtifact < ApplicationRecord
       secret_detection: 'gl-secret-detection-report.json',
       dependency_scanning: 'gl-dependency-scanning-report.json',
       container_scanning: 'gl-container-scanning-report.json',
+      cluster_image_scanning: 'gl-cluster-image-scanning-report.json',
       dast: 'gl-dast-report.json',
       license_scanning: 'gl-license-scanning-report.json',
       performance: 'performance.json',
@@ -71,6 +72,7 @@ class JobArtifact < ApplicationRecord
       secret_detection: :raw,
       dependency_scanning: :raw,
       container_scanning: :raw,
+      cluster_image_scanning: :raw,
       dast: :raw,
       license_scanning: :raw,
 
@@ -108,6 +110,7 @@ class JobArtifact < ApplicationRecord
       sast
       secret_detection
       requirements
+      cluster_image_scanning
     ].freeze
 
     TYPE_AND_FORMAT_PAIRS = INTERNAL_TYPES.merge(REPORT_TYPES).freeze
@@ -212,7 +215,8 @@ class JobArtifact < ApplicationRecord
       coverage_fuzzing: 23, ## EE-specific
       browser_performance: 24, ## EE-specific
       load_performance: 25, ## EE-specific
-      api_fuzzing: 26 ## EE-specific
+      api_fuzzing: 26, ## EE-specific
+      cluster_image_scanning: 27 ## EE-specific
     }
 
     # `file_location` indicates where actual files are stored.
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 4a9c75967a3f12ef956c87a584de4aa193e66f8b..5f8883dde5746b6d886a749a12a13435eb4b2c88 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -14547,6 +14547,7 @@ Iteration ID wildcard values.
 | <a id="jobartifactfiletypearchive"></a>`ARCHIVE` | ARCHIVE job artifact file type. |
 | <a id="jobartifactfiletypebrowser_performance"></a>`BROWSER_PERFORMANCE` | BROWSER PERFORMANCE job artifact file type. |
 | <a id="jobartifactfiletypecluster_applications"></a>`CLUSTER_APPLICATIONS` | CLUSTER APPLICATIONS job artifact file type. |
+| <a id="jobartifactfiletypecluster_image_scanning"></a>`CLUSTER_IMAGE_SCANNING` | CLUSTER IMAGE SCANNING job artifact file type. |
 | <a id="jobartifactfiletypecobertura"></a>`COBERTURA` | COBERTURA job artifact file type. |
 | <a id="jobartifactfiletypecodequality"></a>`CODEQUALITY` | CODE QUALITY job artifact file type. |
 | <a id="jobartifactfiletypecontainer_scanning"></a>`CONTAINER_SCANNING` | CONTAINER SCANNING job artifact file type. |
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index f5f7d427cd90995eb0733ad2712ca768cc041617..f927393e80961d881e91f161e5215391e9ab20a4 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -3064,6 +3064,18 @@ as artifacts.
 The collected coverage fuzzing report uploads to GitLab as an artifact and is summarized in merge
 requests and the pipeline view. It's also used to provide data for security dashboards.
 
+##### `artifacts:reports:cluster_image_scanning` **(ULTIMATE)**
+
+> - Introduced in GitLab 14.1.
+> - Requires GitLab Runner 14.1 and above.
+
+The `cluster_image_scanning` report collects `CLUSTER_IMAGE_SCANNING` vulnerabilities
+as artifacts.
+
+The collected `CLUSTER_IMAGE_SCANNING` report uploads to GitLab as an artifact and
+is summarized in the pipeline view. It's also used to provide data for security
+dashboards.
+
 ##### `artifacts:reports:dast` **(ULTIMATE)**
 
 > - Introduced in GitLab 11.5.
diff --git a/ee/app/graphql/types/vulnerability_location_type.rb b/ee/app/graphql/types/vulnerability_location_type.rb
index 2580c6f6c7bb1b97ab3f3319f32a9cfa99ca5657..897f4a876b9ec690a3fcd54d503a2a03f89e1a12 100644
--- a/ee/app/graphql/types/vulnerability_location_type.rb
+++ b/ee/app/graphql/types/vulnerability_location_type.rb
@@ -16,7 +16,7 @@ class VulnerabilityLocationType < BaseUnion
 
     def self.resolve_type(object, context)
       case object[:report_type]
-      when 'container_scanning'
+      when 'container_scanning', 'cluster_image_scanning'
         VulnerabilityLocation::ContainerScanningType
       when 'dependency_scanning'
         VulnerabilityLocation::DependencyScanningType
diff --git a/ee/app/models/ee/ci/build.rb b/ee/app/models/ee/ci/build.rb
index e117908b7a5a11938df4a9ab035b1e2b67a2220c..5dabacf4bc045756e74d0474b0b718c44654283a 100644
--- a/ee/app/models/ee/ci/build.rb
+++ b/ee/app/models/ee/ci/build.rb
@@ -16,6 +16,7 @@ module Build
         secret_detection: :secret_detection,
         dependency_scanning: :dependency_scanning,
         container_scanning: :container_scanning,
+        cluster_image_scanning: :cluster_image_scanning,
         dast: :dast,
         coverage_fuzzing: :coverage_fuzzing,
         api_fuzzing: :api_fuzzing
diff --git a/ee/app/models/ee/ci/job_artifact.rb b/ee/app/models/ee/ci/job_artifact.rb
index dd80b203525f8b66a8faf8230196f850d7d5d8d6..c46a694ef48806aac7da6174ab966e65696fcd3b 100644
--- a/ee/app/models/ee/ci/job_artifact.rb
+++ b/ee/app/models/ee/ci/job_artifact.rb
@@ -15,11 +15,12 @@ module Ci::JobArtifact
       # See https://gitlab.com/gitlab-org/gitlab/-/issues/297472
       after_destroy :log_geo_deleted_event
 
-      SECURITY_REPORT_FILE_TYPES = %w[sast secret_detection dependency_scanning container_scanning dast coverage_fuzzing api_fuzzing].freeze
+      SECURITY_REPORT_FILE_TYPES = %w[sast secret_detection dependency_scanning container_scanning cluster_image_scanning dast coverage_fuzzing api_fuzzing].freeze
       LICENSE_SCANNING_REPORT_FILE_TYPES = %w[license_scanning].freeze
       DEPENDENCY_LIST_REPORT_FILE_TYPES = %w[dependency_scanning].freeze
       METRICS_REPORT_FILE_TYPES = %w[metrics].freeze
       CONTAINER_SCANNING_REPORT_TYPES = %w[container_scanning].freeze
+      CLUSTER_IMAGE_SCANNING_REPORT_TYPES = %w[cluster_image_scanning].freeze
       DAST_REPORT_TYPES = %w[dast].freeze
       REQUIREMENTS_REPORT_FILE_TYPES = %w[requirements].freeze
       COVERAGE_FUZZING_REPORT_TYPES = %w[coverage_fuzzing].freeze
@@ -44,6 +45,10 @@ module Ci::JobArtifact
         with_file_types(CONTAINER_SCANNING_REPORT_TYPES)
       end
 
+      scope :cluster_image_scanning_reports, -> do
+        with_file_types(CLUSTER_IMAGE_SCANNING_REPORT_TYPES)
+      end
+
       scope :dast_reports, -> do
         with_file_types(DAST_REPORT_TYPES)
       end
diff --git a/ee/app/models/ee/ci/pipeline.rb b/ee/app/models/ee/ci/pipeline.rb
index 95a5db5253936ba61303c58d04602f27fd63221e..da84ed7112eef2df96053dbe2440c6029afb90af 100644
--- a/ee/app/models/ee/ci/pipeline.rb
+++ b/ee/app/models/ee/ci/pipeline.rb
@@ -46,6 +46,7 @@ module Pipeline
           secret_detection: %i[secret_detection],
           dependency_scanning: %i[dependency_scanning],
           container_scanning: %i[container_scanning],
+          cluster_image_scanning: %i[cluster_image_scanning],
           dast: %i[dast],
           performance: %i[merge_request_performance_metrics],
           browser_performance: %i[merge_request_performance_metrics],
diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb
index 8f2778419e3173bbfa553ec3488310e78d324d65..52d71558fb804e9418db7cea7e9bcb274cf4cd7b 100644
--- a/ee/app/models/ee/namespace.rb
+++ b/ee/app/models/ee/namespace.rb
@@ -332,6 +332,7 @@ def store_security_reports_available?
       feature_available?(:secret_detection) ||
       feature_available?(:dependency_scanning) ||
       feature_available?(:container_scanning) ||
+      feature_available?(:cluster_image_scanning) ||
       feature_available?(:dast) ||
       feature_available?(:coverage_fuzzing) ||
       feature_available?(:api_fuzzing)
diff --git a/ee/app/models/license.rb b/ee/app/models/license.rb
index 85ff0df9ca2261c1e9be23a3b3455b730953e045..dff39512a8e5c67ccc94acc75b4be6cf2159cfb5 100644
--- a/ee/app/models/license.rb
+++ b/ee/app/models/license.rb
@@ -144,6 +144,7 @@ class License < ApplicationRecord
     api_fuzzing
     auto_rollback
     cilium_alerts
+    cluster_image_scanning
     external_status_checks
     container_scanning
     coverage_fuzzing
diff --git a/ee/lib/ee/gitlab/ci/parsers.rb b/ee/lib/ee/gitlab/ci/parsers.rb
index 058bedca7d827bdc429d1b3fb6a5a3bfc5cfa2f9..39d845072b63920bcbbdc86be71d9a4e3c2809aa 100644
--- a/ee/lib/ee/gitlab/ci/parsers.rb
+++ b/ee/lib/ee/gitlab/ci/parsers.rb
@@ -12,6 +12,7 @@ def parsers
                 license_scanning: ::Gitlab::Ci::Parsers::LicenseCompliance::LicenseScanning,
                 dependency_scanning: ::Gitlab::Ci::Parsers::Security::DependencyScanning,
                 container_scanning: ::Gitlab::Ci::Parsers::Security::ContainerScanning,
+                cluster_image_scanning: ::Gitlab::Ci::Parsers::Security::ContainerScanning,
                 dast: ::Gitlab::Ci::Parsers::Security::Dast,
                 sast: ::Gitlab::Ci::Parsers::Security::Sast,
                 api_fuzzing: ::Gitlab::Ci::Parsers::Security::Dast,
diff --git a/ee/lib/gitlab/vulnerabilities/parser.rb b/ee/lib/gitlab/vulnerabilities/parser.rb
index 08daddd7e3926ab6778421ca794003b5d52a5377..bd05e914c09b7769c9d27b0d9e51f551ed7dfdf6 100644
--- a/ee/lib/gitlab/vulnerabilities/parser.rb
+++ b/ee/lib/gitlab/vulnerabilities/parser.rb
@@ -25,7 +25,7 @@ def valid_categories
         end
 
         def standard_vulnerability?(category)
-          (valid_categories.keys - ['container_scanning']).include?(category)
+          (valid_categories.keys - %w[container_scanning cluster_image_scanning]).include?(category)
         end
       end
     end
diff --git a/ee/spec/factories/ci/builds.rb b/ee/spec/factories/ci/builds.rb
index dcc5687f7ad9e95b7cd04bc2483767280cd6a256..da2ea8b21317db3940bbc5f0bf5f1efef2aa279c 100644
--- a/ee/spec/factories/ci/builds.rb
+++ b/ee/spec/factories/ci/builds.rb
@@ -6,7 +6,7 @@
       failure_reason { Ci::Build.failure_reasons[:protected_environment_failure] }
     end
 
-    %i[api_fuzzing codequality container_scanning dast dependency_scanning license_scanning performance browser_performance load_performance sast secret_detection coverage_fuzzing].each do |report_type|
+    %i[api_fuzzing codequality container_scanning cluster_image_scanning dast dependency_scanning license_scanning performance browser_performance load_performance sast secret_detection coverage_fuzzing].each do |report_type|
       trait "legacy_#{report_type}".to_sym do
         success
         artifacts
@@ -84,6 +84,18 @@
       end
     end
 
+    trait :cluster_image_scanning_feature_branch do
+      after(:build) do |build|
+        build.job_artifacts << create(:ee_ci_job_artifact, :cluster_image_scanning_feature_branch, job: build)
+      end
+    end
+
+    trait :corrupted_cluster_image_scanning_report do
+      after(:build) do |build|
+        build.job_artifacts << create(:ee_ci_job_artifact, :corrupted_cluster_image_scanning_report, job: build)
+      end
+    end
+
     trait :dependency_scanning_feature_branch do
       after(:build) do |build|
         build.job_artifacts << create(:ee_ci_job_artifact, :dependency_scanning_feature_branch, job: build)
diff --git a/ee/spec/factories/ci/job_artifacts.rb b/ee/spec/factories/ci/job_artifacts.rb
index 189ea29adb519e39b5dd9fe8dd547ebcf468567d..e19e8062ca292c2ac34d8375ce14dc955c102c9a 100644
--- a/ee/spec/factories/ci/job_artifacts.rb
+++ b/ee/spec/factories/ci/job_artifacts.rb
@@ -299,6 +299,16 @@
       end
     end
 
+    trait :cluster_image_scanning do
+      file_format { :raw }
+      file_type { :cluster_image_scanning }
+
+      after(:build) do |artifact, _|
+        artifact.file = fixture_file_upload(
+          Rails.root.join('ee/spec/fixtures/security_reports/master/gl-cluster-image-scanning-report.json'), 'application/json')
+      end
+    end
+
     trait :common_security_report do
       file_format { :raw }
       file_type { :dependency_scanning }
@@ -339,6 +349,26 @@
       end
     end
 
+    trait :cluster_image_scanning_feature_branch do
+      file_format { :raw }
+      file_type { :cluster_image_scanning }
+
+      after(:build) do |artifact, _|
+        artifact.file = fixture_file_upload(
+          Rails.root.join('ee/spec/fixtures/security_reports/feature-branch/gl-cluster-image-scanning-report.json'), 'application/json')
+      end
+    end
+
+    trait :corrupted_cluster_image_scanning_report do
+      file_format { :raw }
+      file_type { :cluster_image_scanning }
+
+      after(:build) do |artifact, _|
+        artifact.file = fixture_file_upload(
+          Rails.root.join('spec/fixtures/trace/sample_trace'), 'application/json')
+      end
+    end
+
     trait :metrics do
       file_format { :gzip }
       file_type { :metrics }
diff --git a/ee/spec/factories/ci/pipelines.rb b/ee/spec/factories/ci/pipelines.rb
index 9dad575d039fa0cdd391e9efddd693647b5651ed..e3e5d555cce80d2a67b33e20608b0a698bf9db08 100644
--- a/ee/spec/factories/ci/pipelines.rb
+++ b/ee/spec/factories/ci/pipelines.rb
@@ -2,7 +2,7 @@
 
 FactoryBot.define do
   factory :ee_ci_pipeline, class: 'Ci::Pipeline', parent: :ci_pipeline do
-    %i[api_fuzzing browser_performance codequality container_scanning coverage_fuzzing dast dependency_list dependency_scanning license_scanning load_performance sast secret_detection].each do |report_type|
+    %i[api_fuzzing browser_performance codequality container_scanning cluster_image_scanning coverage_fuzzing dast dependency_list dependency_scanning license_scanning load_performance sast secret_detection].each do |report_type|
       trait "with_#{report_type}_report".to_sym do
         status { :success }
 
@@ -28,6 +28,22 @@
       end
     end
 
+    trait :with_cluster_image_scanning_feature_branch do
+      status { :success }
+
+      after(:build) do |pipeline, evaluator|
+        pipeline.builds << build(:ee_ci_build, :cluster_image_scanning_feature_branch, pipeline: pipeline, project: pipeline.project)
+      end
+    end
+
+    trait :with_corrupted_cluster_image_scanning_report do
+      status { :success }
+
+      after(:build) do |pipeline, evaluator|
+        pipeline.builds << build(:ee_ci_build, :corrupted_cluster_image_scanning_report, pipeline: pipeline, project: pipeline.project)
+      end
+    end
+
     trait :with_dependency_scanning_feature_branch do
       status { :success }
 
diff --git a/ee/spec/factories/vulnerabilities/feedback.rb b/ee/spec/factories/vulnerabilities/feedback.rb
index 34b81bd469d99dd3b846e85f6b7fed0b1718727c..66495bc67bbecc8c234ca267ac9a633189892b76 100644
--- a/ee/spec/factories/vulnerabilities/feedback.rb
+++ b/ee/spec/factories/vulnerabilities/feedback.rb
@@ -52,6 +52,10 @@
       category { 'container_scanning' }
     end
 
+    trait :cluster_image_scanning do
+      category { 'cluster_image_scanning' }
+    end
+
     trait :dast do
       category { 'dast' }
     end
diff --git a/ee/spec/fixtures/security_reports/feature-branch/gl-cluster-image-scanning-report.json b/ee/spec/fixtures/security_reports/feature-branch/gl-cluster-image-scanning-report.json
new file mode 100644
index 0000000000000000000000000000000000000000..7fd44870cc6157081fc19654098ffa8cecb652d0
--- /dev/null
+++ b/ee/spec/fixtures/security_reports/feature-branch/gl-cluster-image-scanning-report.json
@@ -0,0 +1,56 @@
+{
+  "version": "2.4",
+  "vulnerabilities": [
+    {
+      "id": "e987fa54ff94e1d0e716814861459d2eb10bd27a0ba8ca243428669d8885ce68",
+      "category": "cluster_image_scanning",
+      "message": "CVE-2017-15650 in musl",
+      "description": "musl:1.1.18-r3 is affected by CVE-2017-15650",
+      "cve": "alpine:v3.7:musl:CVE-2017-15650",
+      "severity": "High",
+      "confidence": "Unknown",
+      "solution": "Upgrade musl from 1.1.18-r3 to 1.1.18-r4",
+      "scanner": {
+        "id": "starboard",
+        "name": "Starboard"
+      },
+      "location": {
+        "dependency": {
+          "package": {
+            "name": "musl"
+          },
+          "version": "1.1.18-r3"
+        },
+        "operating_system": "alpine:v3.7",
+        "image": "registry.gitlab.com/bikebilly/auto-devops-10-6/feature-branch:e7315ba964febb11bac8f5cd6ec433db8a3a1583"
+      },
+      "identifiers": [
+        {
+          "type": "cve",
+          "name": "CVE-2017-15650",
+          "value": "CVE-2017-15650",
+          "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15650"
+        }
+      ],
+      "links": [
+        {
+          "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15650"
+        }
+      ]
+    }
+  ],
+  "remediations": [],
+  "scan": {
+    "scanner": {
+      "id": "starboard",
+      "name": "Starboard",
+      "url": "https://github.com/aquasecurity/starboard",
+      "vendor": {
+        "name": "GitLab"
+      },
+      "version": "2.1.4"
+    },
+    "type": "cluster_image_scanning",
+    "status": "success"
+  }
+}
diff --git a/ee/spec/fixtures/security_reports/master/gl-cluster-image-scanning-report.json b/ee/spec/fixtures/security_reports/master/gl-cluster-image-scanning-report.json
new file mode 100644
index 0000000000000000000000000000000000000000..c8fa795d6479a175eb5f23cb602054492bfcc4cb
--- /dev/null
+++ b/ee/spec/fixtures/security_reports/master/gl-cluster-image-scanning-report.json
@@ -0,0 +1,91 @@
+{
+  "version": "2.3",
+  "vulnerabilities": [
+    {
+      "category": "cluster_image_scanning",
+      "message": "CVE-2017-18269 in glibc",
+      "description": "An SSE2-optimized memmove implementation for i386 in sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S in the GNU C Library (aka glibc or libc6) 2.21 through 2.27 does not correctly perform the overlapping memory check if the source memory range spans the middle of the address space, resulting in corrupt data being produced by the copy operation. This may disclose information to context-dependent attackers, or result in a denial of service, or, possibly, code execution.",
+      "cve": "debian:9:glibc:CVE-2017-18269",
+      "severity": "Critical",
+      "confidence": "Unknown",
+      "solution": "Upgrade glibc from 2.24-11+deb9u3 to 2.24-11+deb9u4",
+      "scanner": {
+        "id": "starboard",
+        "name": "Starboard"
+      },
+      "location": {
+        "dependency": {
+          "package": {
+            "name": "glibc"
+          },
+          "version": "2.24-11+deb9u3"
+        },
+        "operating_system": "debian:9",
+        "image": "registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e"
+      },
+      "identifiers": [
+        {
+          "type": "cve",
+          "name": "CVE-2017-18269",
+          "value": "CVE-2017-18269",
+          "url": "https://security-tracker.debian.org/tracker/CVE-2017-18269"
+        }
+      ],
+      "links": [
+        {
+          "url": "https://security-tracker.debian.org/tracker/CVE-2017-18269"
+        }
+      ]
+    },
+    {
+      "category": "cluster_image_scanning",
+      "message": "CVE-2017-16997 in glibc",
+      "description": "elf/dl-load.c in the GNU C Library (aka glibc or libc6) 2.19 through 2.26 mishandles RPATH and RUNPATH containing $ORIGIN for a privileged (setuid or AT_SECURE) program, which allows local users to gain privileges via a Trojan horse library in the current working directory, related to the fillin_rpath and decompose_rpath functions. This is associated with misinterpretion of an empty RPATH/RUNPATH token as the \"./\" directory. NOTE: this configuration of RPATH/RUNPATH for a privileged program is apparently very uncommon; most likely, no such program is shipped with any common Linux distribution.",
+      "cve": "debian:9:glibc:CVE-2017-16997",
+      "severity": "Critical",
+      "confidence": "Unknown",
+      "solution": "Upgrade glibc from 2.24-11+deb9u3 to 2.24-11+deb9u4",
+      "scanner": {
+        "id": "starboard",
+        "name": "Starboard"
+      },
+      "location": {
+        "dependency": {
+          "package": {
+            "name": "glibc"
+          },
+          "version": "2.24-11+deb9u3"
+        },
+        "operating_system": "debian:9",
+        "image": "registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e"
+      },
+      "identifiers": [
+        {
+          "type": "cve",
+          "name": "CVE-2017-16997",
+          "value": "CVE-2017-16997",
+          "url": "https://security-tracker.debian.org/tracker/CVE-2017-16997"
+        }
+      ],
+      "links": [
+        {
+          "url": "https://security-tracker.debian.org/tracker/CVE-2017-16997"
+        }
+      ]
+    }
+  ],
+  "remediations": [],
+  "scan": {
+    "scanner": {
+      "id": "starboard",
+      "name": "Starboard",
+      "url": "https://github.com/aquasecurity/starboard",
+      "vendor": {
+        "name": "GitLab"
+      },
+      "version": "0.10.0"
+    },
+    "type": "cluster_image_scanning",
+    "status": "success"
+  }
+}
diff --git a/ee/spec/lib/gitlab/vulnerabilities/parser_spec.rb b/ee/spec/lib/gitlab/vulnerabilities/parser_spec.rb
index 5f7499f0475187a8cdf404574f30d63c582fda4c..2328b5cb2c403c938c504674ea84b336f8b1434e 100644
--- a/ee/spec/lib/gitlab/vulnerabilities/parser_spec.rb
+++ b/ee/spec/lib/gitlab/vulnerabilities/parser_spec.rb
@@ -39,6 +39,15 @@
       end
     end
 
+    context 'with cluster image scanning as category' do
+      it 'returns a Scanning Vulnerability' do
+        params[:category] = 'cluster_image_scanning'
+
+        expect(subject).to be_a(Gitlab::Vulnerabilities::ContainerScanningVulnerability)
+        expect(subject.target_branch).to eq('master')
+      end
+    end
+
     context 'with an invalid category' do
       it 'raises an exception' do
         params[:category] = 'foo'
diff --git a/ee/spec/models/ci/pipeline_spec.rb b/ee/spec/models/ci/pipeline_spec.rb
index 4ca156dc697b510c8b774d44b5ff7290a5bac2eb..21469a2b06671f75f96d606fabf2d320dfc9f475 100644
--- a/ee/spec/models/ci/pipeline_spec.rb
+++ b/ee/spec/models/ci/pipeline_spec.rb
@@ -109,7 +109,7 @@
     subject { pipeline.security_reports }
 
     before do
-      stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true)
+      stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true, cluster_image_scanning: true)
     end
 
     context 'when pipeline has multiple builds with security reports' do
@@ -119,12 +119,16 @@
       let(:build_ds_2) { create(:ci_build, :success, name: 'ds_2', pipeline: pipeline, project: project) }
       let(:build_cs_1) { create(:ci_build, :success, name: 'cs_1', pipeline: pipeline, project: project) }
       let(:build_cs_2) { create(:ci_build, :success, name: 'cs_2', pipeline: pipeline, project: project) }
+      let(:build_cis_1) { create(:ci_build, :success, name: 'cis_1', pipeline: pipeline, project: project) }
+      let(:build_cis_2) { create(:ci_build, :success, name: 'cis_2', pipeline: pipeline, project: project) }
       let!(:sast1_artifact) { create(:ee_ci_job_artifact, :sast, job: build_sast_1, project: project) }
       let!(:sast2_artifact) { create(:ee_ci_job_artifact, :sast, job: build_sast_2, project: project) }
       let!(:ds1_artifact) { create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds_1, project: project) }
       let!(:ds2_artifact) { create(:ee_ci_job_artifact, :dependency_scanning, job: build_ds_2, project: project) }
       let!(:cs1_artifact) { create(:ee_ci_job_artifact, :container_scanning, job: build_cs_1, project: project) }
       let!(:cs2_artifact) { create(:ee_ci_job_artifact, :container_scanning, job: build_cs_2, project: project) }
+      let!(:cis1_artifact) { create(:ee_ci_job_artifact, :cluster_image_scanning, job: build_cis_1, project: project) }
+      let!(:cis2_artifact) { create(:ee_ci_job_artifact, :cluster_image_scanning, job: build_cis_2, project: project) }
 
       it 'assigns pipeline to the reports' do
         expect(subject.pipeline).to eq(pipeline)
@@ -132,12 +136,13 @@
       end
 
       it 'returns security reports with collected data grouped as expected' do
-        expect(subject.reports.keys).to contain_exactly('sast', 'dependency_scanning', 'container_scanning')
+        expect(subject.reports.keys).to contain_exactly('sast', 'dependency_scanning', 'container_scanning', 'cluster_image_scanning')
 
         # for each of report categories, we have merged 2 reports with the same data (fixture)
         expect(subject.get_report('sast', sast1_artifact).findings.size).to eq(5)
         expect(subject.get_report('dependency_scanning', ds1_artifact).findings.size).to eq(4)
         expect(subject.get_report('container_scanning', cs1_artifact).findings.size).to eq(8)
+        expect(subject.get_report('cluster_image_scanning', cis1_artifact).findings.size).to eq(2)
       end
 
       context 'when builds are retried' do
@@ -147,6 +152,7 @@
           expect(subject.get_report('sast', sast1_artifact).findings.size).to eq(5)
           expect(subject.get_report('dependency_scanning', ds1_artifact).findings.size).to eq(4)
           expect(subject.get_report('container_scanning', cs1_artifact).findings.size).to eq(8)
+          expect(subject.get_report('cluster_image_scanning', cis1_artifact).findings.size).to eq(2)
         end
       end
 
@@ -535,18 +541,22 @@
     where(:pipeline_status, :build_types, :expected_status) do
       [
         [:blocked, [:container_scanning], false],
+        [:blocked, [:cluster_image_scanning], false],
         [:blocked, [:license_scan_v2_1, :container_scanning], true],
         [:blocked, [:license_scan_v2_1], true],
         [:blocked, [], false],
         [:failed, [:container_scanning], false],
+        [:failed, [:cluster_image_scanning], false],
         [:failed, [:license_scan_v2_1, :container_scanning], true],
         [:failed, [:license_scan_v2_1], true],
         [:failed, [], false],
         [:running, [:container_scanning], false],
+        [:running, [:cluster_image_scanning], false],
         [:running, [:license_scan_v2_1, :container_scanning], true],
         [:running, [:license_scan_v2_1], true],
         [:running, [], false],
         [:success, [:container_scanning], false],
+        [:success, [:cluster_image_scanning], false],
         [:success, [:license_scan_v2_1, :container_scanning], true],
         [:success, [:license_scan_v2_1], true],
         [:success, [], false]
diff --git a/ee/spec/models/ee/ci/job_artifact_spec.rb b/ee/spec/models/ee/ci/job_artifact_spec.rb
index 4514b15fc742f11f45e15d939c6f2491526c0654..1b59e6e1a56ce91cd1c05c566dfd9ec2d1066da7 100644
--- a/ee/spec/models/ee/ci/job_artifact_spec.rb
+++ b/ee/spec/models/ee/ci/job_artifact_spec.rb
@@ -31,6 +31,14 @@
     it { is_expected.to eq([artifact]) }
   end
 
+  describe '.cluster_image_scanning_reports' do
+    subject { Ci::JobArtifact.cluster_image_scanning_reports }
+
+    let_it_be(:artifact) { create(:ee_ci_job_artifact, :cluster_image_scanning) }
+
+    it { is_expected.to eq([artifact]) }
+  end
+
   describe '.metrics_reports' do
     subject { Ci::JobArtifact.metrics_reports }
 
@@ -226,13 +234,14 @@
 
     context 'for different types' do
       where(:file_type, :security_report?) do
-        :performance         | false
-        :sast                | true
-        :secret_detection    | true
-        :dependency_scanning | true
-        :container_scanning  | true
-        :dast                | true
-        :coverage_fuzzing    | true
+        :performance            | false
+        :sast                   | true
+        :secret_detection       | true
+        :dependency_scanning    | true
+        :container_scanning     | true
+        :cluster_image_scanning | true
+        :dast                   | true
+        :coverage_fuzzing       | true
       end
 
       with_them do
diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb
index bc5e6e770763c4260509278b7b8ad37ac26d5e3f..8ad06f32e2a4dc0388578f1a817cc8e0d5042fe7 100644
--- a/ee/spec/models/ee/namespace_spec.rb
+++ b/ee/spec/models/ee/namespace_spec.rb
@@ -1314,7 +1314,7 @@
     subject { namespace.store_security_reports_available? }
 
     context 'when at least one security report feature is enabled' do
-      where(report_type: [:sast, :secret_detection, :dast, :dependency_scanning, :container_scanning])
+      where(report_type: [:sast, :secret_detection, :dast, :dependency_scanning, :container_scanning, :cluster_image_scanning])
 
       with_them do
         before do
diff --git a/ee/spec/requests/api/graphql/vulnerabilities/location_spec.rb b/ee/spec/requests/api/graphql/vulnerabilities/location_spec.rb
index 0c906af370eafe9edf867db59bdb82c105f085a1..2bdf8fa17ad6e7130a35e9c10a9a0e94e4f3b29a 100644
--- a/ee/spec/requests/api/graphql/vulnerabilities/location_spec.rb
+++ b/ee/spec/requests/api/graphql/vulnerabilities/location_spec.rb
@@ -110,6 +110,45 @@
     end
   end
 
+  context 'when the vulnerability was found by a cluster image scan' do
+    let_it_be(:vulnerability) do
+      create(:vulnerability, project: project, report_type: :cluster_image_scanning)
+    end
+
+    let_it_be(:metadata) do
+      {
+        location: {
+          image: 'vulnerable_image',
+          operating_system: 'vulnerable_os',
+          dependency: {
+            version: '6.6.6',
+            package: {
+              name: 'vulnerable_container'
+            }
+          }
+        }
+      }
+    end
+
+    let_it_be(:finding) do
+      create(
+        :vulnerabilities_finding,
+        vulnerability: vulnerability,
+        raw_metadata: metadata.to_json
+      )
+    end
+
+    it 'returns a container location' do
+      location = subject.first['location']
+
+      expect(location['__typename']).to eq('VulnerabilityLocationContainerScanning')
+      expect(location['image']).to eq('vulnerable_image')
+      expect(location['operatingSystem']).to eq('vulnerable_os')
+      expect(location['dependency']['version']).to eq('6.6.6')
+      expect(location['dependency']['package']['name']).to eq('vulnerable_container')
+    end
+  end
+
   context 'when the vulnerability was found by a dependency scan' do
     let_it_be(:vulnerability) do
       create(:vulnerability, project: project, report_type: :dependency_scanning)
diff --git a/ee/spec/workers/store_security_reports_worker_spec.rb b/ee/spec/workers/store_security_reports_worker_spec.rb
index 1d54ce5e69b96b4a14f6088a6d4d87186b75e2ef..ba2f51c43d1ff76b4c918063fb3a207d356066e7 100644
--- a/ee/spec/workers/store_security_reports_worker_spec.rb
+++ b/ee/spec/workers/store_security_reports_worker_spec.rb
@@ -56,7 +56,7 @@
     end
 
     context 'when at least one security report feature is enabled' do
-      where(report_type: [:sast, :dast, :dependency_scanning, :container_scanning])
+      where(report_type: [:sast, :dast, :dependency_scanning, :container_scanning, :cluster_image_scanning])
 
       with_them do
         before do
diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb
index 4db25fb09308a9a0b02776c836cdf91cdd07246d..e45dbfa243fda265a0f3dd708510f5f35f816fa1 100644
--- a/lib/gitlab/ci/config/entry/reports.rb
+++ b/lib/gitlab/ci/config/entry/reports.rb
@@ -15,7 +15,7 @@ class Reports < ::Gitlab::Config::Entry::Node
             %i[junit codequality sast secret_detection dependency_scanning container_scanning
                dast performance browser_performance load_performance license_scanning metrics lsif
                dotenv cobertura terraform accessibility cluster_applications
-               requirements coverage_fuzzing api_fuzzing].freeze
+               requirements coverage_fuzzing api_fuzzing cluster_image_scanning].freeze
 
           attributes ALLOWED_KEYS
 
@@ -32,6 +32,7 @@ class Reports < ::Gitlab::Config::Entry::Node
               validates :secret_detection, array_of_strings_or_string: true
               validates :dependency_scanning, array_of_strings_or_string: true
               validates :container_scanning, array_of_strings_or_string: true
+              validates :cluster_image_scanning, array_of_strings_or_string: true
               validates :dast, array_of_strings_or_string: true
               validates :performance, array_of_strings_or_string: true
               validates :browser_performance, array_of_strings_or_string: true
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 395d3ea598c000b055de78654aaaf6fb265abcde..0e535aeaa8d79d1f23a3ab381ef555d147ec8e2e 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -508,6 +508,14 @@
       end
     end
 
+    trait :cluster_image_scanning do
+      options do
+        {
+            artifacts: { reports: { cluster_image_scanning: 'gl-cluster-image-scanning-report.json' } }
+        }
+      end
+    end
+
     trait :license_scanning do
       options do
         {
diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
index d8907f7015b0aa8b612fe94f18173e7addeb86d3..12b8960eb329d0def28ad9cc74272d25ecad3576 100644
--- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
@@ -40,6 +40,7 @@
         :secret_detection | 'gl-secret-detection-report.json'
         :dependency_scanning | 'gl-dependency-scanning-report.json'
         :container_scanning | 'gl-container-scanning-report.json'
+        :cluster_image_scanning | 'gl-cluster-image-scanning-report.json'
         :dast | 'gl-dast-report.json'
         :license_scanning | 'gl-license-scanning-report.json'
         :performance | 'performance.json'
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 87893f11ed542e4603f61389f27b27e1e85f7f3b..42d6e66b38b961c0e4e8c5267a76f9565dc02712 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -39,7 +39,7 @@
        erased_at auto_canceled_by job_artifacts job_artifacts_archive
        job_artifacts_metadata job_artifacts_trace job_artifacts_junit
        job_artifacts_sast job_artifacts_secret_detection job_artifacts_dependency_scanning
-       job_artifacts_container_scanning job_artifacts_dast
+       job_artifacts_container_scanning job_artifacts_cluster_image_scanning job_artifacts_dast
        job_artifacts_license_scanning
        job_artifacts_performance job_artifacts_browser_performance job_artifacts_load_performance
        job_artifacts_lsif job_artifacts_terraform job_artifacts_cluster_applications