diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/tokens/status_token.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/tokens/status_token.vue
new file mode 100644
index 0000000000000000000000000000000000000000..003f51340b4ef4d059aca57c986aa79585c75441
--- /dev/null
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/tokens/status_token.vue
@@ -0,0 +1,187 @@
+<script>
+import {
+  GlIcon,
+  GlFilteredSearchToken,
+  GlFilteredSearchSuggestion,
+  GlDropdownDivider,
+  GlDropdownSectionHeader,
+} from '@gitlab/ui';
+import { VULNERABILITY_STATE_OBJECTS } from 'ee/vulnerabilities/constants';
+import { getSelectedOptionsText } from '~/lib/utils/listbox_helpers';
+import { s__, n__ } from '~/locale';
+import { GROUPS } from '../../filters/status_filter.vue';
+import { ALL_ID as ALL_STATUS_VALUE } from '../../filters/constants';
+
+const { detected, confirmed } = VULNERABILITY_STATE_OBJECTS;
+
+const ALL_DISMISSED_VALUE = GROUPS[1].options[0].value;
+const DISMISSAL_REASON_VALUES = GROUPS[1].options.slice(1).map(({ value }) => value);
+const DEFAULT_VALUES = [detected.searchParamValue, confirmed.searchParamValue];
+
+export default {
+  DEFAULT_VALUES,
+  GROUPS,
+
+  components: {
+    GlIcon,
+    GlFilteredSearchToken,
+    GlFilteredSearchSuggestion,
+    GlDropdownDivider,
+    GlDropdownSectionHeader,
+  },
+  props: {
+    config: {
+      type: Object,
+      required: true,
+    },
+    // contains the token, with the selected operand (e.g.: '=') and the data (comma separated, e.g.: 'MIT, GNU')
+    value: {
+      type: Object,
+      required: true,
+    },
+    active: {
+      type: Boolean,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      searchTerm: '',
+      selectedStatuses: [...DEFAULT_VALUES],
+    };
+  },
+  computed: {
+    tokenValue() {
+      return {
+        ...this.value,
+        // when the token is active (dropdown is open), we set the value to null to prevent an UX issue
+        // in which only the last selected item is being displayed.
+        // more information: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2381
+        data: this.active ? null : this.selectedStatuses,
+      };
+    },
+    toggleText() {
+      // "All dismissal reasons" option is selected
+      if (this.selectedStatuses.length === 1 && this.selectedStatuses[0] === ALL_DISMISSED_VALUE) {
+        return s__('SecurityReports|Dismissed (all reasons)');
+      }
+
+      // Dismissal reason(s) is selected
+      if (this.selectedStatuses.every((value) => DISMISSAL_REASON_VALUES.includes(value))) {
+        return n__(`Dismissed (%d reason)`, `Dismissed (%d reasons)`, this.selectedStatuses.length);
+      }
+
+      return getSelectedOptionsText({
+        options: [...GROUPS[0].options, ...GROUPS[1].options],
+        selected: this.selectedStatuses,
+      });
+    },
+  },
+  methods: {
+    setSearchTerm(token) {
+      // the data can be either a string or an array, in which case we don't want to perform the search
+      if (typeof token.data === 'string') {
+        this.searchTerm = token.data.toLowerCase();
+      }
+    },
+    toggleSelectedStatus(selectedValue) {
+      const allStatusSelected = selectedValue === ALL_STATUS_VALUE;
+      const allDismissedSelected = selectedValue === ALL_DISMISSED_VALUE;
+
+      // Unselect
+      if (this.selectedStatuses.includes(selectedValue)) {
+        this.selectedStatuses = this.selectedStatuses.filter((s) => s !== selectedValue);
+
+        if (this.selectedStatuses.length) {
+          return;
+        }
+      }
+
+      // If there is no option selected or the All Statuses option is selected, simply set
+      // the array to ALL_STATUS_VALUE
+      if (!this.selectedStatuses.length || allStatusSelected) {
+        this.selectedStatuses = [ALL_STATUS_VALUE];
+        return;
+      }
+
+      // Remove other dismissal values when All Dismissed option is selected
+      if (allDismissedSelected) {
+        this.selectedStatuses = this.selectedStatuses.filter(
+          (s) => !DISMISSAL_REASON_VALUES.includes(s),
+        );
+      }
+      // When a dismissal reason is selected, unselect All Dismissed option
+      else if (DISMISSAL_REASON_VALUES.includes(selectedValue)) {
+        this.selectedStatuses = this.selectedStatuses.filter((s) => s !== ALL_DISMISSED_VALUE);
+      }
+
+      // Otherwise select the item. Make sure to unselect ALL_STATUS_VALUE anyways because
+      this.selectedStatuses = this.selectedStatuses.filter((s) => s !== ALL_STATUS_VALUE);
+      this.selectedStatuses.push(selectedValue);
+    },
+    isStatusSelected(name) {
+      return Boolean(this.selectedStatuses.find((s) => name === s));
+    },
+  },
+  groups: {
+    statusOptions: GROUPS[0].options,
+    dismissalReasonOptions: GROUPS[1].options,
+  },
+  i18n: {
+    statusLabel: s__('SecurityReports|Status'),
+    dismissedAsLabel: GROUPS[1].text,
+  },
+};
+</script>
+
+<template>
+  <gl-filtered-search-token
+    :config="config"
+    v-bind="{ ...$props, ...$attrs }"
+    :multi-select-values="selectedStatuses"
+    :value="tokenValue"
+    v-on="$listeners"
+    @select="toggleSelectedStatus"
+    @input="setSearchTerm"
+  >
+    <template #view>
+      {{ toggleText }}
+    </template>
+    <template #suggestions>
+      <gl-dropdown-section-header>{{ $options.i18n.statusLabel }}</gl-dropdown-section-header>
+      <gl-dropdown-divider />
+      <gl-filtered-search-suggestion
+        v-for="status in $options.groups.statusOptions"
+        :key="status.value"
+        :value="status.value"
+      >
+        <div class="gl-display-flex gl-align-items-center">
+          <gl-icon
+            name="check"
+            class="gl-mr-3 gl-flex-shrink-0 gl-text-gray-700"
+            :class="{ 'gl-visibility-hidden': !isStatusSelected(status.value) }"
+            :data-testid="`status-icon-${status.value}`"
+          />
+          {{ status.text }}
+        </div>
+      </gl-filtered-search-suggestion>
+      <gl-dropdown-divider />
+      <gl-dropdown-section-header>{{ $options.i18n.dismissedAsLabel }}</gl-dropdown-section-header>
+      <gl-filtered-search-suggestion
+        v-for="status in $options.groups.dismissalReasonOptions"
+        :key="status.value"
+        :value="status.value"
+      >
+        <div class="gl-display-flex gl-align-items-center">
+          <gl-icon
+            name="check"
+            class="gl-mr-3 gl-flex-shrink-0 gl-text-gray-700"
+            :class="{ 'gl-visibility-hidden': !isStatusSelected(status.value) }"
+            :data-testid="`status-icon-${status.value}`"
+          />
+          {{ status.text }}
+        </div>
+      </gl-filtered-search-suggestion>
+    </template>
+  </gl-filtered-search-token>
+</template>
diff --git a/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search.vue b/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search.vue
index 6e29a27469d4f8553e3969a4522cc623b35e84f9..b4b41ccf9f0c5a95a37fe09e17c6494990cf9a7f 100644
--- a/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search.vue
+++ b/ee/app/assets/javascripts/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search.vue
@@ -1,5 +1,7 @@
 <script>
 import { GlFilteredSearch } from '@gitlab/ui';
+import { OPERATORS_IS, OPERATOR_IS } from '~/vue_shared/components/filtered_search_bar/constants';
+import StatusToken from './tokens/status_token.vue';
 
 export default {
   components: {
@@ -7,13 +9,29 @@ export default {
   },
   data() {
     return {
-      value: [],
-      currentFilterParams: null,
+      value: [
+        {
+          type: 'status',
+          value: {
+            data: StatusToken.DEFAULT_VALUES,
+            operator: OPERATOR_IS,
+          },
+        },
+      ],
     };
   },
   computed: {
     tokens() {
-      return [];
+      return [
+        {
+          type: 'status',
+          title: StatusToken.i18n.statusLabel,
+          multiSelect: true,
+          unique: true,
+          token: StatusToken,
+          operators: OPERATORS_IS,
+        },
+      ];
     },
   },
 };
@@ -23,6 +41,7 @@ export default {
   <gl-filtered-search
     :placeholder="s__('Vulnerability|Search or filter vulnerabilities...')"
     :available-tokens="tokens"
+    :value="value"
     terms-as-tokens
   />
 </template>
diff --git a/ee/spec/frontend/security_dashboard/components/shared/filtered_search/tokens/status_token_spec.js b/ee/spec/frontend/security_dashboard/components/shared/filtered_search/tokens/status_token_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..50ce45b39d1a3266ee2c82ce92093fee8f12c3f2
--- /dev/null
+++ b/ee/spec/frontend/security_dashboard/components/shared/filtered_search/tokens/status_token_spec.js
@@ -0,0 +1,186 @@
+import { GlFilteredSearchToken } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import StatusToken from 'ee/security_dashboard/components/shared/filtered_search/tokens/status_token.vue';
+import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
+import { stubComponent } from 'helpers/stub_component';
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+describe('Status Token component', () => {
+  let wrapper;
+
+  const mockConfig = {
+    multiSelect: true,
+    unique: true,
+    operators: OPERATORS_IS,
+  };
+
+  const createWrapper = ({
+    value = { data: StatusToken.DEFAULT_VALUES, operator: '=' },
+    active = false,
+    stubs,
+    mountFn = shallowMountExtended,
+  } = {}) => {
+    wrapper = mountFn(StatusToken, {
+      propsData: {
+        config: mockConfig,
+        value,
+        active,
+      },
+      provide: {
+        portalName: 'fake target',
+        alignSuggestions: jest.fn(),
+        termsAsTokens: () => false,
+      },
+
+      stubs,
+    });
+  };
+
+  const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+  const findCheckedIcon = (value) => wrapper.findByTestId(`status-icon-${value}`);
+
+  const clickDropdownItem = async (...ids) => {
+    await Promise.all(
+      ids.map((id) => {
+        findFilteredSearchToken().vm.$emit('select', id);
+        return nextTick();
+      }),
+    );
+
+    await nextTick();
+  };
+
+  const allOptionsExcept = (value) => {
+    return StatusToken.GROUPS.flatMap((i) => i.options)
+      .map((i) => i.value)
+      .filter((i) => i !== value);
+  };
+
+  describe('default view', () => {
+    const findSlotView = () => wrapper.findByTestId('slot-view');
+    const findSlotSuggestions = () => wrapper.findByTestId('slot-suggestions');
+
+    beforeEach(() => {
+      createWrapper({
+        stubs: {
+          GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
+            template: `
+            <div>
+                <div data-testid="slot-view">
+                    <slot name="view"></slot>
+                </div>
+                <div data-testid="slot-suggestions">
+                    <slot name="suggestions"></slot>
+                </div>
+            </div>`,
+          }),
+        },
+      });
+    });
+
+    it('shows the label', () => {
+      expect(findSlotView().text()).toBe('Needs triage +1 more');
+    });
+
+    it('shows the dropdown with correct options', () => {
+      expect(
+        findSlotSuggestions()
+          .text()
+          .split('\n')
+          .map((s) => s.trim())
+          .filter((i) => i),
+      ).toEqual([
+        'Status', // subheader
+        'All statuses',
+        'Needs triage',
+        'Confirmed',
+        'Resolved',
+        'Dismissed as...', // subheader
+        'All dismissal reasons',
+        'Acceptable risk',
+        'False positive',
+        'Mitigating control',
+        'Used in tests',
+        'Not applicable',
+      ]);
+    });
+  });
+
+  describe('item selection', () => {
+    beforeEach(async () => {
+      createWrapper({});
+      await clickDropdownItem('ALL');
+    });
+
+    it('toggles the item selection when clicked on', async () => {
+      const isOptionChecked = (v) => !findCheckedIcon(v).classes('gl-visibility-hidden');
+
+      await clickDropdownItem('CONFIRMED', 'RESOLVED');
+
+      expect(isOptionChecked('ALL')).toBe(false);
+      expect(isOptionChecked('CONFIRMED')).toBe(true);
+      expect(isOptionChecked('RESOLVED')).toBe(true);
+
+      // Add a dismissal reason
+      await clickDropdownItem('ACCEPTABLE_RISK');
+
+      expect(isOptionChecked('CONFIRMED')).toBe(true);
+      expect(isOptionChecked('RESOLVED')).toBe(true);
+      expect(isOptionChecked('ACCEPTABLE_RISK')).toBe(true);
+      expect(isOptionChecked('DISMISSED')).toBe(false);
+
+      // Select all
+      await clickDropdownItem('ALL');
+
+      allOptionsExcept('ALL').forEach((value) => {
+        expect(isOptionChecked(value)).toBe(false);
+      });
+
+      // Select All Dismissed Values
+      await clickDropdownItem('DISMISSED');
+
+      allOptionsExcept('DISMISSED').forEach((value) => {
+        expect(isOptionChecked(value)).toBe(false);
+      });
+
+      // Selecting another dismissed should unselect All Dismissed values
+      await clickDropdownItem('USED_IN_TESTS');
+
+      expect(isOptionChecked('USED_IN_TESTS')).toBe(true);
+      expect(isOptionChecked('DISMISSED')).toBe(false);
+    });
+  });
+
+  describe('toggle text', () => {
+    const findSlotView = () => wrapper.findAllByTestId('filtered-search-token-segment').at(2);
+
+    beforeEach(async () => {
+      createWrapper({ value: {}, mountFn: mountExtended });
+
+      // Let's set initial state as ALL. It's easier to manipulate because
+      // selecting a new value should unselect this value automatically and
+      // we can start from an empty state.
+      await clickDropdownItem('ALL');
+    });
+
+    it('shows "Dismissed (all reasons)" when only "All dismissal reasons" option is selected', async () => {
+      await clickDropdownItem('DISMISSED');
+      expect(findSlotView().text()).toBe('Dismissed (all reasons)');
+    });
+
+    it('shows "Dismissed (2 reasons)" when only 2 dismissal reasons are selected', async () => {
+      await clickDropdownItem('FALSE_POSITIVE', 'ACCEPTABLE_RISK');
+      expect(findSlotView().text()).toBe('Dismissed (2 reasons)');
+    });
+
+    it('shows "Confirmed +1 more" when confirmed and a dismissal reason are selected', async () => {
+      await clickDropdownItem('CONFIRMED', 'FALSE_POSITIVE');
+      expect(findSlotView().text()).toBe('Confirmed +1 more');
+    });
+
+    it('shows "Confirmed +1 more" when confirmed and all dismissal reasons are selected', async () => {
+      await clickDropdownItem('CONFIRMED', 'DISMISSED');
+      expect(findSlotView().text()).toBe('Confirmed +1 more');
+    });
+  });
+});
diff --git a/ee/spec/frontend/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search_spec.js b/ee/spec/frontend/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c571ae5a640219844b3fedf77d8b16c4bfe6c30
--- /dev/null
+++ b/ee/spec/frontend/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search_spec.js
@@ -0,0 +1,46 @@
+import { GlFilteredSearch } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import FilteredSearch from 'ee/security_dashboard/components/shared/filtered_search/vulnerability_report_filtered_search.vue';
+import StatusToken from 'ee/security_dashboard/components/shared/filtered_search/tokens/status_token.vue';
+import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
+
+describe('Vulnerability Report Filtered Search component', () => {
+  let wrapper;
+
+  const findFilteredSearchComponent = () => wrapper.findComponent(GlFilteredSearch);
+
+  const createWrapper = () => {
+    wrapper = mountExtended(FilteredSearch);
+  };
+
+  beforeEach(() => {
+    createWrapper();
+  });
+
+  it('should mount the component with the correct config', () => {
+    const filteredSearch = findFilteredSearchComponent();
+
+    expect(filteredSearch.props('placeholder')).toEqual('Search or filter vulnerabilities...');
+
+    expect(filteredSearch.props('value')).toEqual([
+      {
+        type: 'status',
+        value: {
+          data: StatusToken.DEFAULT_VALUES,
+          operator: '=',
+        },
+      },
+    ]);
+
+    expect(filteredSearch.props('availableTokens')).toEqual([
+      {
+        type: 'status',
+        title: 'Status',
+        multiSelect: true,
+        unique: true,
+        token: StatusToken,
+        operators: OPERATORS_IS,
+      },
+    ]);
+  });
+});