diff --git a/app/assets/javascripts/security_configuration/graphql/set_container_scanning_for_registry.graphql b/app/assets/javascripts/security_configuration/graphql/set_container_scanning_for_registry.graphql
new file mode 100644
index 0000000000000000000000000000000000000000..843f0edbe0251e7aa9d58b9073d038aab0eca457
--- /dev/null
+++ b/app/assets/javascripts/security_configuration/graphql/set_container_scanning_for_registry.graphql
@@ -0,0 +1,6 @@
+mutation SetContainerScanningForRegistry($input: SetContainerScanningForRegistryInput!) {
+  setContainerScanningForRegistry(input: $input) {
+    containerScanningForRegistryEnabled
+    errors
+  }
+}
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index d8c0ac3daa1e4194a1ea4759b2eb77044e7b857d..6ac9cb548cd2b51aacd0224838ee42e26f84ce8b 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -7825,6 +7825,28 @@ Input type: `SecurityTrainingUpdateInput`
 | <a id="mutationsecuritytrainingupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
 | <a id="mutationsecuritytrainingupdatetraining"></a>`training` | [`ProjectSecurityTraining`](#projectsecuritytraining) | Represents the training entity subject to mutation. |
 
+### `Mutation.setContainerScanningForRegistry`
+
+Enable/disable Container Scanning on Container Registry for the given project or group.
+
+Input type: `SetContainerScanningForRegistryInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationsetcontainerscanningforregistryclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationsetcontainerscanningforregistryenable"></a>`enable` | [`Boolean!`](#boolean) | Desired status for Container Scanning on Container Registry feature. |
+| <a id="mutationsetcontainerscanningforregistrynamespacepath"></a>`namespacePath` | [`ID!`](#id) | Full path of the namespace (project or group). |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationsetcontainerscanningforregistryclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationsetcontainerscanningforregistrycontainerscanningforregistryenabled"></a>`containerScanningForRegistryEnabled` | [`Boolean`](#boolean) | Whether the feature is enabled. |
+| <a id="mutationsetcontainerscanningforregistryerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
 ### `Mutation.setPreReceiveSecretDetection`
 
 Enable/disable pre-receive secret detection for the given project.
diff --git a/ee/app/graphql/ee/types/mutation_type.rb b/ee/app/graphql/ee/types/mutation_type.rb
index e1c7941aa447f3a59e01f611dae5ad6450025d6b..f51bc21a93532be0d2659fbf4960b74fe55c3a9d 100644
--- a/ee/app/graphql/ee/types/mutation_type.rb
+++ b/ee/app/graphql/ee/types/mutation_type.rb
@@ -149,6 +149,7 @@ module MutationType
         mount_mutation ::Mutations::AuditEvents::Streaming::InstanceEventTypeFilters::Destroy
         mount_mutation ::Mutations::Security::CiConfiguration::ProjectSetContinuousVulnerabilityScanning
         mount_mutation ::Mutations::Security::CiConfiguration::SetPreReceiveSecretDetection
+        mount_mutation ::Mutations::Security::CiConfiguration::SetContainerScanningForRegistry
         mount_mutation ::Mutations::AuditEvents::Instance::GoogleCloudLoggingConfigurations::Destroy
         mount_mutation ::Mutations::AuditEvents::Instance::GoogleCloudLoggingConfigurations::Update
         mount_mutation ::Mutations::DependencyProxy::Packages::Settings::Update
diff --git a/ee/app/graphql/mutations/security/ci_configuration/set_container_scanning_for_registry.rb b/ee/app/graphql/mutations/security/ci_configuration/set_container_scanning_for_registry.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cc110bcf45050c443515ebc4e900aadd748e0ed6
--- /dev/null
+++ b/ee/app/graphql/mutations/security/ci_configuration/set_container_scanning_for_registry.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Security
+    module CiConfiguration
+      class SetContainerScanningForRegistry < BaseMutation
+        graphql_name 'SetContainerScanningForRegistry'
+
+        include FindsNamespace
+
+        description <<~DESC
+          Enable/disable Container Scanning on Container Registry for the given project or group.
+        DESC
+
+        argument :namespace_path, GraphQL::Types::ID,
+          required: true,
+          description: 'Full path of the namespace (project or group).'
+
+        argument :enable, GraphQL::Types::Boolean,
+          required: true,
+          description: 'Desired status for Container Scanning on Container Registry feature.'
+
+        field :container_scanning_for_registry_enabled, GraphQL::Types::Boolean,
+          null: true,
+          description: 'Whether the feature is enabled.'
+
+        authorize :enable_container_scanning_for_registry
+
+        def resolve(namespace_path:, enable:)
+          namespace = find_namespace(namespace_path)
+
+          response = ::Security::Configuration::SetContainerScanningForRegistryService
+            .execute(namespace: namespace, enable: enable)
+
+          { container_scanning_for_registry_enabled: response.payload[:enabled], errors: response.errors }
+        end
+
+        private
+
+        def find_namespace(namespace_path)
+          namespace = authorized_find!(namespace_path)
+          # This will be removed following the completion of https://gitlab.com/gitlab-org/gitlab/-/issues/451430
+          unless namespace.is_a? Project
+            raise_resource_not_available_error! 'Setting only available for Project namespaces.'
+          end
+
+          namespace
+        end
+      end
+    end
+  end
+end
diff --git a/ee/app/policies/ee/group_policy.rb b/ee/app/policies/ee/group_policy.rb
index 65c26c830b0145c7e57d93f9e78dd41156b182c5..9427d209c130b12d197263447c890de4e6660209 100644
--- a/ee/app/policies/ee/group_policy.rb
+++ b/ee/app/policies/ee/group_policy.rb
@@ -769,6 +769,14 @@ module GroupPolicy
       rule { pre_receive_secret_detection_available & can?(:maintainer_access) }.policy do
         enable :enable_pre_receive_secret_detection
       end
+
+      condition(:container_scanning_for_registry_available) do
+        ::Feature.enabled?(:container_scanning_for_registry)
+      end
+
+      rule { container_scanning_for_registry_available & can?(:maintainer_access) }.policy do
+        enable :enable_container_scanning_for_registry
+      end
     end
 
     override :lookup_access_level!
diff --git a/ee/app/policies/ee/project_policy.rb b/ee/app/policies/ee/project_policy.rb
index 3191ba2943ccdd981a47a7732ae683d69e01f224..b80cc52aa8c2d2dfe51386a6394298b6f4c6fc3b 100644
--- a/ee/app/policies/ee/project_policy.rb
+++ b/ee/app/policies/ee/project_policy.rb
@@ -981,6 +981,14 @@ module ProjectPolicy
       rule { pre_receive_secret_detection_available & can?(:maintainer_access) }.policy do
         enable :enable_pre_receive_secret_detection
       end
+
+      condition(:container_scanning_for_registry_available) do
+        ::Feature.enabled?(:container_scanning_for_registry)
+      end
+
+      rule { container_scanning_for_registry_available & can?(:maintainer_access) }.policy do
+        enable :enable_container_scanning_for_registry
+      end
     end
 
     override :lookup_access_level!
diff --git a/ee/app/services/security/configuration/set_container_scanning_for_registry_service.rb b/ee/app/services/security/configuration/set_container_scanning_for_registry_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ca1f157de21b8538b3066ef2db56e147b0e12927
--- /dev/null
+++ b/ee/app/services/security/configuration/set_container_scanning_for_registry_service.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Security
+  module Configuration
+    class SetContainerScanningForRegistryService
+      def self.execute(namespace:, enable:)
+        # At present, the security_setting feature is exclusively accessible for projects.
+        # Following the resolution of https://gitlab.com/gitlab-org/gitlab/-/issues/451430,
+        # this feature will also be available at the group level.
+        ServiceResponse.success(
+          payload: {
+            enabled: namespace.security_setting.set_container_scanning_for_registry!(
+              enabled: enable
+            ),
+            errors: []
+          })
+      rescue StandardError => e
+        ServiceResponse.error(
+          message: e.message,
+          payload: { enabled: nil }
+        )
+      end
+    end
+  end
+end
diff --git a/ee/config/feature_flags/wip/container_scanning_for_registry.yml b/ee/config/feature_flags/wip/container_scanning_for_registry.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6c6e4a20db4a0c1f4a237b93099fca81aa96142b
--- /dev/null
+++ b/ee/config/feature_flags/wip/container_scanning_for_registry.yml
@@ -0,0 +1,9 @@
+---
+name: container_scanning_for_registry
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/442890
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147537
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/443827
+milestone: '17.0'
+group: group::composition analysis
+type: wip
+default_enabled: false
diff --git a/ee/spec/policies/group_policy_spec.rb b/ee/spec/policies/group_policy_spec.rb
index 2c801ac8a61e1d770cbad52c409d9ec674c6bb2c..790219fbe749ef95cd91fa66bdf9e279db01498b 100644
--- a/ee/spec/policies/group_policy_spec.rb
+++ b/ee/spec/policies/group_policy_spec.rb
@@ -3640,4 +3640,25 @@ def create_member_role(member, abilities = member_role_abilities)
       it { is_expected.to match_expected_result }
     end
   end
+
+  describe 'enable_container_scanning_for_registry' do
+    using RSpec::Parameterized::TableSyntax
+
+    where(:container_scanning_for_registry, :current_user, :match_expected_result) do
+      true  | ref(:owner)      | be_allowed(:enable_container_scanning_for_registry)
+      true  | ref(:maintainer) | be_allowed(:enable_container_scanning_for_registry)
+      true  | ref(:developer)  | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:owner)      | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:maintainer) | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:developer)  | be_disallowed(:enable_container_scanning_for_registry)
+    end
+
+    with_them do
+      before do
+        stub_feature_flags(container_scanning_for_registry: container_scanning_for_registry)
+      end
+
+      it { is_expected.to match_expected_result }
+    end
+  end
 end
diff --git a/ee/spec/policies/project_policy_spec.rb b/ee/spec/policies/project_policy_spec.rb
index 299e6776e0edc7f2faf8e71b60f626eef5a42c32..3e10496743ae238cca76099e7fafa021d79c977d 100644
--- a/ee/spec/policies/project_policy_spec.rb
+++ b/ee/spec/policies/project_policy_spec.rb
@@ -3807,4 +3807,27 @@ def create_member_role(member, abilities = member_role_abilities)
       it { is_expected.to match_expected_result }
     end
   end
+
+  describe 'enable_container_scanning_for_registry' do
+    using RSpec::Parameterized::TableSyntax
+
+    where(:container_scanning_for_registry, :current_user, :match_expected_result) do
+      true  | ref(:owner)      | be_allowed(:enable_container_scanning_for_registry)
+      true  | ref(:maintainer) | be_allowed(:enable_container_scanning_for_registry)
+      true  | ref(:developer)  | be_disallowed(:enable_container_scanning_for_registry)
+      true  | ref(:non_member) | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:owner)      | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:maintainer) | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:developer)  | be_disallowed(:enable_container_scanning_for_registry)
+      false | ref(:non_member) | be_disallowed(:enable_container_scanning_for_registry)
+    end
+
+    with_them do
+      before do
+        stub_feature_flags(container_scanning_for_registry: container_scanning_for_registry)
+      end
+
+      it { is_expected.to match_expected_result }
+    end
+  end
 end
diff --git a/ee/spec/requests/api/graphql/mutations/security/configuration/set_container_scanning_for_registry_spec.rb b/ee/spec/requests/api/graphql/mutations/security/configuration/set_container_scanning_for_registry_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7d6702db5aabf2d9ed9c28424a330da32e5b81f2
--- /dev/null
+++ b/ee/spec/requests/api/graphql/mutations/security/configuration/set_container_scanning_for_registry_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Setting Project and Group Container Scanning for Registry', feature_category: :software_composition_analysis do
+  using RSpec::Parameterized::TableSyntax
+  include GraphqlHelpers
+
+  let(:current_user) { create(:user) }
+  let(:security_setting) { create(:project_security_setting, container_scanning_for_registry_enabled: value_before) }
+  let(:mutation_name) { :set_container_scanning_for_registry }
+
+  let(:value_before) { false }
+  let(:enable) { true }
+
+  context 'with project' do
+    let(:project) { security_setting.project }
+    let(:mutation) do
+      graphql_mutation(
+        mutation_name,
+        namespace_path: project.full_path,
+        enable: enable
+      )
+    end
+
+    context 'when the user does not have permission' do
+      it_behaves_like 'a mutation that returns a top-level access error'
+
+      it 'does not enable container scanning for registry' do
+        expect { post_graphql_mutation(mutation, current_user: current_user) }
+          .not_to change { security_setting.reload.container_scanning_for_registry_enabled }
+      end
+    end
+
+    context 'when the user has permission' do
+      before do
+        project.add_maintainer(current_user)
+      end
+
+      where(:value_before, :enable, :value_after) do
+        true  | false | false
+        true  | true  | true
+        false | true  | true
+        false | false | false
+      end
+
+      with_them do
+        it 'updates the namespace setting and returns the new value' do
+          post_graphql_mutation(mutation, current_user: current_user)
+
+          response = graphql_mutation_response(mutation_name)
+          expect(response).to include({ 'containerScanningForRegistryEnabled' => value_after, 'errors' => [] })
+
+          expect(security_setting.reload.container_scanning_for_registry_enabled).to eq(value_after)
+        end
+      end
+
+      context 'when an invalid value is provided' do
+        let(:enable) { true }
+        let(:value_before) { false }
+
+        before do
+          allow(::Security::Configuration::SetContainerScanningForRegistryService).to receive(:execute).and_return(
+            ServiceResponse.error(message: 'failed', payload: { enabled: nil })
+          )
+        end
+
+        it 'returns an error' do
+          post_graphql_mutation(mutation, current_user: current_user)
+
+          response = graphql_mutation_response(mutation_name)
+          expect(response).to include({ 'containerScanningForRegistryEnabled' => nil, 'errors' => be_present })
+
+          expect(security_setting.reload.container_scanning_for_registry_enabled).to eq(false)
+        end
+      end
+    end
+  end
+
+  context 'with group' do
+    let(:group) { create(:group) }
+    let(:mutation) do
+      graphql_mutation(
+        mutation_name,
+        namespace_path: group.full_path,
+        enable: enable
+      )
+    end
+
+    context 'when the user does not have permission' do
+      it_behaves_like 'a mutation that returns a top-level access error'
+
+      it 'does not enable container scanning for registry' do
+        expect { post_graphql_mutation(mutation, current_user: current_user) }
+          .not_to change { security_setting.reload.container_scanning_for_registry_enabled }
+      end
+    end
+
+    context 'when the user has permission' do
+      before do
+        group.add_maintainer(current_user)
+      end
+
+      it 'raises ResourceNotAvailable' do
+        post_graphql_mutation(mutation, current_user: current_user)
+
+        expect_graphql_errors_to_include('Setting only available for Project namespaces.')
+      end
+    end
+  end
+end
diff --git a/ee/spec/services/security/configuration/set_container_scanning_for_registry_service_spec.rb b/ee/spec/services/security/configuration/set_container_scanning_for_registry_service_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6caa41909b08ffc9df930209f1a96de0c4d4d5b8
--- /dev/null
+++ b/ee/spec/services/security/configuration/set_container_scanning_for_registry_service_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Security::Configuration::SetContainerScanningForRegistryService, feature_category: :software_composition_analysis do
+  describe '#execute' do
+    let_it_be(:security_setting) { create(:project_security_setting, container_scanning_for_registry_enabled: false) }
+
+    context 'when namespace is project' do
+      let_it_be(:namespace) { security_setting.project }
+
+      it 'returns attribute value' do
+        expect(described_class.execute(namespace: namespace,
+          enable: true)).to have_attributes(errors: be_blank, payload: include(enabled: true))
+        expect(described_class.execute(namespace: namespace,
+          enable: false)).to have_attributes(errors: be_blank, payload: include(enabled: false))
+      end
+
+      it 'changes the attribute' do
+        expect { described_class.execute(namespace: namespace, enable: true) }
+          .to change { security_setting.reload.container_scanning_for_registry_enabled }
+          .from(false).to(true)
+        expect { described_class.execute(namespace: namespace, enable: true) }
+          .not_to change { security_setting.reload.container_scanning_for_registry_enabled }
+        expect { described_class.execute(namespace: namespace, enable: false) }
+          .to change { security_setting.reload.container_scanning_for_registry_enabled }
+          .from(true).to(false)
+        expect { described_class.execute(namespace: namespace, enable: false) }
+          .not_to change { security_setting.reload.container_scanning_for_registry_enabled }
+      end
+
+      context 'when fields are invalid' do
+        context 'when repository_path_pattern is invalid' do
+          it 'returns nil and error' do
+            expect(described_class.execute(namespace: namespace,
+              enable: nil)).to have_attributes(errors: be_present, payload: include(enabled: nil))
+          end
+
+          it 'does not change the attribute' do
+            expect { described_class.execute(namespace: namespace, enable: nil) }
+              .not_to change { security_setting.reload.container_scanning_for_registry_enabled }
+          end
+        end
+      end
+    end
+  end
+end