diff --git a/config/feature_flags/development/group_level_vulnerability_report_grouping.yml b/config/feature_flags/development/group_level_vulnerability_report_grouping.yml
new file mode 100644
index 0000000000000000000000000000000000000000..163d46f6b62aece7184a03ab99cf8328fe3fd9a1
--- /dev/null
+++ b/config/feature_flags/development/group_level_vulnerability_report_grouping.yml
@@ -0,0 +1,8 @@
+---
+name: group_level_vulnerability_report_grouping
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137778
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/432778
+milestone: '16.7'
+type: development
+group: group::threat insights
+default_enabled: false
diff --git a/ee/app/assets/javascripts/security_dashboard/components/group/group_vulnerability_report.vue b/ee/app/assets/javascripts/security_dashboard/components/group/group_vulnerability_report.vue
index a83f1e9f919de4d1ec359a5ccd1a45cf5d3a1f94..67e2ba579093666991d17e9f5b2daa233d3dbdbc 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/group/group_vulnerability_report.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/group/group_vulnerability_report.vue
@@ -8,6 +8,9 @@ export default {
     VulnerabilityReportTabs,
   },
   inject: ['hasProjects'],
+  provide: {
+    isGroupVulnerabilityReport: true,
+  },
 };
 </script>
 
diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_report.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_report.vue
index f8e6acdaab2d10d11ff3373696c5a1fd52ac4617..36b0451ccead62933629dc81ecc2bc95255cd199 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_report.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_report.vue
@@ -11,6 +11,7 @@ import { createAlert } from '~/alert';
 import countsQuery from 'ee/security_dashboard/graphql/queries/vulnerability_severities_count.query.graphql';
 import SummaryHighlights from 'ee/vue_shared/security_reports/components/summary_highlights.vue';
 import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import { __, s__ } from '~/locale';
 import { getIdFromGraphQLId } from '~/graphql_shared/utils';
 import { scrollToElement, contentTop } from '~/lib/utils/common_utils';
@@ -54,10 +55,14 @@ export default {
     GlSprintf,
     UserCalloutDismisser,
   },
+  mixins: [glFeatureFlagsMixin()],
   inject: {
     fullPath: {
       default: '',
     },
+    isGroupVulnerabilityReport: {
+      default: false,
+    },
     isProjectVulnerabilityReport: {
       default: false,
     },
@@ -109,7 +114,18 @@ export default {
       return this.filterDropdowns.includes(FILTERS.PROJECT);
     },
     shouldShowGroupByButton() {
-      return this.isProjectVulnerabilityReport && this.isVisible;
+      if (!this.isVisible) {
+        return false;
+      }
+
+      if (
+        this.isGroupVulnerabilityReport &&
+        this.glFeatures.groupLevelVulnerabilityReportGrouping
+      ) {
+        return true;
+      }
+
+      return this.isProjectVulnerabilityReport;
     },
     groups() {
       if (!this.groupBy) {
@@ -310,8 +326,8 @@ export default {
           const queryName = `groupCounts.${value}`;
           const variables = {
             fullPath: this.fullPath,
-            isProject: true,
-            isGroup: false,
+            isProject: this.isProjectVulnerabilityReport,
+            isGroup: this.isGroupVulnerabilityReport,
             isInstance: false,
             ...this.graphqlFilters,
             ...this.formatGroupFilters(value),
@@ -329,8 +345,10 @@ export default {
               return variables;
             },
             update(data) {
-              this.$set(this.groupCounts, value, data.project?.vulnerabilitySeveritiesCount);
-              return data.project?.vulnerabilitySeveritiesCount;
+              const level = this.isProjectVulnerabilityReport ? 'project' : 'group';
+
+              this.$set(this.groupCounts, value, data[level]?.vulnerabilitySeveritiesCount);
+              return data[level]?.vulnerabilitySeveritiesCount;
             },
             error() {
               createAlert({
diff --git a/ee/app/controllers/groups/security/vulnerabilities_controller.rb b/ee/app/controllers/groups/security/vulnerabilities_controller.rb
index 38eeaed1ea15cd8cec2b4103274ee7c4fcc2f623..ac219c8b990a2e48bb5af0b5b863161fddfb7116 100644
--- a/ee/app/controllers/groups/security/vulnerabilities_controller.rb
+++ b/ee/app/controllers/groups/security/vulnerabilities_controller.rb
@@ -14,6 +14,7 @@ class VulnerabilitiesController < Groups::ApplicationController
       before_action do
         push_frontend_feature_flag(:activity_filter_has_mr, @project)
         push_frontend_feature_flag(:activity_filter_has_remediations, @project)
+        push_frontend_feature_flag(:group_level_vulnerability_report_grouping, @project)
       end
 
       def index
diff --git a/ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_report_spec.js b/ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_report_spec.js
index 0a5a88ca1ea165269e46e395a2e14a0e5bc626db..9e879f1be7ccf64b49a52e96ff413d60ff1411be 100644
--- a/ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_report_spec.js
+++ b/ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_report_spec.js
@@ -40,7 +40,9 @@ describe('Vulnerability report component', () => {
     fullPath,
     filterFn,
     scanners,
+    isGroupVulnerabilityReport,
     isProjectVulnerabilityReport = true,
+    glFeatures,
     shouldShowCallout = false,
   } = {}) => {
     router = new VueRouter({
@@ -54,9 +56,11 @@ describe('Vulnerability report component', () => {
       apolloProvider,
       router,
       provide: {
+        isGroupVulnerabilityReport,
         isProjectVulnerabilityReport,
         fullPath,
         scanners,
+        glFeatures,
       },
       propsData: {
         query,
@@ -212,13 +216,14 @@ describe('Vulnerability report component', () => {
     });
   });
 
-  describe('group by', () => {
+  describe.each`
+    dashboardType
+    ${DASHBOARD_TYPES.PROJECT}
+    ${DASHBOARD_TYPES.GROUP}
+  `('group by: $dashboardType', ({ dashboardType }) => {
     const counts = { critical: 1, high: 2, medium: 5, low: 4, info: 3, unknown: 6 };
 
-    const getCountsRequestHandler = ({
-      data = counts,
-      dashboardType = DASHBOARD_TYPES.PROJECT,
-    } = {}) => {
+    const getCountsRequestHandler = ({ data = counts } = {}) => {
       return jest.fn().mockResolvedValue({
         data: {
           [dashboardType]: {
@@ -249,10 +254,17 @@ describe('Vulnerability report component', () => {
     } = {}) => {
       createWrapper({
         apolloProvider: createMockApollo([[countsQuery, getCountsRequestHandler()]]),
-        isProjectVulnerabilityReport: true,
+        isProjectVulnerabilityReport: dashboardType === DASHBOARD_TYPES.PROJECT,
+        isGroupVulnerabilityReport: dashboardType === DASHBOARD_TYPES.GROUP,
         fullPath: 'gitlab-org/gitlab',
         shouldShowCallout,
         scanners,
+        glFeatures:
+          DASHBOARD_TYPES.GROUP === dashboardType
+            ? {
+                groupLevelVulnerabilityReportGrouping: true,
+              }
+            : {},
       });
 
       // Reset filters
@@ -267,26 +279,6 @@ describe('Vulnerability report component', () => {
       await waitForPromises();
     };
 
-    it.each`
-      isProjectVulnerabilityReport | isVisible | shouldDisplay
-      ${false}                     | ${true}   | ${false}
-      ${true}                      | ${true}   | ${true}
-      ${true}                      | ${false}  | ${false}
-    `(
-      'displays the group by button correctly ' +
-        'project: $isProjectVulnerabilityReport, ' +
-        'isVisible: $isVisible, ' +
-        'should display: $shouldDisplay',
-      ({ isProjectVulnerabilityReport, isVisible, shouldDisplay }) => {
-        createWrapper({
-          isProjectVulnerabilityReport,
-          isVisible,
-        });
-
-        expect(findGroupByButton().exists()).toBe(shouldDisplay);
-      },
-    );
-
     it('displays the group by label', () => {
       createWrapperWithFilters();
       expect(wrapper.findByText('Group by:').exists()).toBe(true);