diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index 81b0fad47a0408d0f65562f282808ca1394affe9..d72ad6694340939e43c6c3103d42f6f4858e82ea 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -179,6 +179,7 @@
     "MergeRequest",
     "Namespace",
     "Project",
+    "Vulnerability",
     "WorkItem"
   ],
   "User": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 933910880c5517675d559baf299496b17800a70b..9d39ad712e792c218b6e5100af18b73363ad8702 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -34399,6 +34399,7 @@ Represents a vulnerability.
 | <a id="vulnerabilitylinks"></a>`links` | [`[VulnerabilityLink!]!`](#vulnerabilitylink) | List of links associated with the vulnerability. |
 | <a id="vulnerabilitylocation"></a>`location` | [`VulnerabilityLocation`](#vulnerabilitylocation) | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability. |
 | <a id="vulnerabilitymergerequest"></a>`mergeRequest` | [`MergeRequest`](#mergerequest) | Merge request that fixes the vulnerability. |
+| <a id="vulnerabilityname"></a>`name` | [`String`](#string) | Name or title of this object. |
 | <a id="vulnerabilitypresentondefaultbranch"></a>`presentOnDefaultBranch` | [`Boolean!`](#boolean) | Indicates whether the vulnerability is present on the default branch or not. |
 | <a id="vulnerabilityprimaryidentifier"></a>`primaryIdentifier` | [`VulnerabilityIdentifier`](#vulnerabilityidentifier) | Primary identifier of the vulnerability. |
 | <a id="vulnerabilityproject"></a>`project` | [`Project`](#project) | Project on which the vulnerability was found. |
@@ -38672,6 +38673,7 @@ Sort options for todos.
 | <a id="todotargetenummergerequest"></a>`MERGEREQUEST` | Merge request. |
 | <a id="todotargetenumnamespace"></a>`NAMESPACE` | Namespace. |
 | <a id="todotargetenumproject"></a>`PROJECT` | Project. |
+| <a id="todotargetenumvulnerability"></a>`VULNERABILITY` | Vulnerability. |
 | <a id="todotargetenumworkitem"></a>`WORKITEM` | Work item. |
 
 ### `TrainingUrlRequestStatus`
@@ -40855,6 +40857,7 @@ Implementations:
 - [`MergeRequest`](#mergerequest)
 - [`Namespace`](#namespace)
 - [`Project`](#project)
+- [`Vulnerability`](#vulnerability)
 - [`WorkItem`](#workitem)
 
 ##### Fields
diff --git a/doc/api/todos.md b/doc/api/todos.md
index bd49128f1873ee47372d8f4333813db6417f1e60..f84084c8a986f1af773c4d223bba468eb6708f1e 100644
--- a/doc/api/todos.md
+++ b/doc/api/todos.md
@@ -31,7 +31,7 @@ Parameters:
 | `project_id` | integer | no | The ID of a project                                                                                                                                                                                |
 | `group_id` | integer | no | The ID of a group                                                                                                                                                                                  |
 | `state` | string | no | The state of the to-do item. Can be either `pending` or `done`                                                                                                                                     |
-| `type` | string | no | The type of to-do item. Can be either `Issue`, `MergeRequest`, `Commit`, `Epic`, `DesignManagement::Design` or `AlertManagement::Alert`                                                            |
+| `type` | string | no | The type of to-do item. Can be either `Issue`, `MergeRequest`, `Commit`, `Epic`, `DesignManagement::Design`, `AlertManagement::Alert`, `Project`, `Namespace` or `Vulnerability`                   |
 
 ```shell
 curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos"
diff --git a/ee/app/finders/ee/todos_finder.rb b/ee/app/finders/ee/todos_finder.rb
index eece83c6e97965f4b4a2089d6ff09c4e9cadbd52..25f0af4a4b5bf63c995571c6bc4cca1019adccf2 100644
--- a/ee/app/finders/ee/todos_finder.rb
+++ b/ee/app/finders/ee/todos_finder.rb
@@ -4,7 +4,7 @@ module EE
   module TodosFinder
     extend ActiveSupport::Concern
 
-    EE_TODO_TYPES = (::TodosFinder::TODO_TYPES + %w[Epic]).freeze
+    EE_TODO_TYPES = (::TodosFinder::TODO_TYPES + %w[Epic Vulnerability]).freeze
 
     class_methods do
       extend ::Gitlab::Utils::Override
diff --git a/ee/app/graphql/ee/types/todo_target_enum.rb b/ee/app/graphql/ee/types/todo_target_enum.rb
index 6f3ff5926ebceae4f5942eac01e7d0b7a05d33e7..52422d2e448ad230d2463c092a9a2ec606026541 100644
--- a/ee/app/graphql/ee/types/todo_target_enum.rb
+++ b/ee/app/graphql/ee/types/todo_target_enum.rb
@@ -7,6 +7,7 @@ module TodoTargetEnum
 
       prepended do
         value 'EPIC', value: 'Epic', description: 'An Epic.'
+        value 'VULNERABILITY', value: 'Vulnerability', description: 'Vulnerability.'
       end
     end
   end
diff --git a/ee/app/graphql/ee/types/todoable_interface.rb b/ee/app/graphql/ee/types/todoable_interface.rb
index dcf3480c61246a6f8fda463302608f8d54fa9fe1..ea46754e16c15e2870f835931ef23f728e2ab23e 100644
--- a/ee/app/graphql/ee/types/todoable_interface.rb
+++ b/ee/app/graphql/ee/types/todoable_interface.rb
@@ -10,9 +10,14 @@ module TodoableInterface
 
         override :resolve_type
         def resolve_type(object, *)
-          return ::Types::EpicType if Epic === object
-
-          super
+          case object
+          when Epic
+            ::Types::EpicType
+          when Vulnerability
+            ::Types::VulnerabilityType
+          else
+            super
+          end
         end
       end
     end
diff --git a/ee/app/graphql/types/vulnerability_type.rb b/ee/app/graphql/types/vulnerability_type.rb
index 12c4e0d77c53142464eec53a199adc1c4b41cdd0..286017e16170540cf4d70dd05097a25d4ecc309b 100644
--- a/ee/app/graphql/types/vulnerability_type.rb
+++ b/ee/app/graphql/types/vulnerability_type.rb
@@ -6,6 +6,7 @@ class VulnerabilityType < BaseObject
     description 'Represents a vulnerability'
 
     implements Types::Notes::NoteableInterface
+    implements Types::TodoableInterface
 
     authorize :read_vulnerability
 
diff --git a/ee/app/models/ee/todo.rb b/ee/app/models/ee/todo.rb
index 85655f318fb79ef44ba41fb4c69ca72de2c2497a..3cc49b1fb4b26e74f63d006d9f02bf8a43614526 100644
--- a/ee/app/models/ee/todo.rb
+++ b/ee/app/models/ee/todo.rb
@@ -14,7 +14,7 @@ def target_url
       return if target.nil?
 
       case target
-      when Epic
+      when Vulnerability, Epic
         ::Gitlab::UrlBuilder.build(
           target,
           anchor: note.present? ? ActionView::RecordIdentifier.dom_id(note) : nil
diff --git a/ee/app/models/ee/vulnerability.rb b/ee/app/models/ee/vulnerability.rb
index a0142ce56840e005f119c94a2da484c17f81b87f..61e552840b0e524fb1a5fe930440d4b114b39db1 100644
--- a/ee/app/models/ee/vulnerability.rb
+++ b/ee/app/models/ee/vulnerability.rb
@@ -3,6 +3,7 @@
 module EE
   module Vulnerability
     include ::Gitlab::Utils::StrongMemoize
+    include Todoable
     extend ActiveSupport::Concern
 
     prepended do
diff --git a/ee/spec/graphql/ee/types/todoable_interface_spec.rb b/ee/spec/graphql/ee/types/todoable_interface_spec.rb
index 2ec1f7ba095741ff2ee29987735bf345e356457a..d4d64e2c107c21cc5fb26be8f782f39aae9afb16 100644
--- a/ee/spec/graphql/ee/types/todoable_interface_spec.rb
+++ b/ee/spec/graphql/ee/types/todoable_interface_spec.rb
@@ -2,12 +2,13 @@
 
 require 'spec_helper'
 
-RSpec.describe Types::TodoableInterface do
+RSpec.describe Types::TodoableInterface, feature_category: :notifications do
   let(:extended_class) { described_class }
 
   describe ".resolve_type" do
     it 'knows the correct type for EE-only objects' do
       expect(extended_class.resolve_type(build(:epic), {})).to eq(Types::EpicType)
+      expect(extended_class.resolve_type(build(:vulnerability), {})).to eq(Types::VulnerabilityType)
     end
   end
 end
diff --git a/ee/spec/graphql/types/vulnerability_type_spec.rb b/ee/spec/graphql/types/vulnerability_type_spec.rb
index bd0ec90a32a5ba75863b97e911ed3a454c1865cc..7165a37f0652eca494339f85f78b9a625146d1c2 100644
--- a/ee/spec/graphql/types/vulnerability_type_spec.rb
+++ b/ee/spec/graphql/types/vulnerability_type_spec.rb
@@ -37,6 +37,7 @@
       report_type
       resolved_on_default_branch
       vulnerability_path
+      name
       web_url
       location
       scanner
@@ -93,6 +94,7 @@
 
   subject(:graphql_response) { GitlabSchema.execute(query, context: { current_user: user }).as_json }
 
+  it { expect(described_class.interfaces).to include(Types::TodoableInterface) }
   it { expect(described_class).to have_graphql_fields(fields) }
   it { expect(described_class).to require_graphql_authorizations(:read_vulnerability) }
 
diff --git a/ee/spec/models/todo_spec.rb b/ee/spec/models/todo_spec.rb
index 9c10bb4e3849ed0294dac7868a02af5820a8d452..151bc175c3c4a4a6d5fbbf7b99d6220be2d3f3a9 100644
--- a/ee/spec/models/todo_spec.rb
+++ b/ee/spec/models/todo_spec.rb
@@ -2,15 +2,16 @@
 
 require 'spec_helper'
 
-RSpec.describe Todo, feature_category: :team_planning do
+RSpec.describe Todo, feature_category: :notifications do
   let_it_be(:current_user) { create(:user) }
-  let_it_be(:group) { create(:group, developers: current_user) }
-  let_it_be(:epic) { create(:epic, group: group) }
 
   describe '#target_url' do
     subject { todo.target_url }
 
     context 'when the todo is coming from an epic' do
+      let_it_be(:group) { create(:group, developers: current_user) }
+      let_it_be(:epic) { create(:epic, group: group) }
+
       context 'when coming from the epic itself' do
         let_it_be(:todo) { create(:todo, project: nil, group: group, user: current_user, target: epic) }
 
@@ -28,5 +29,31 @@
         end
       end
     end
+
+    context 'when the todo is coming from a vulnerability' do
+      let_it_be(:project) { create(:project) }
+      let_it_be(:vulnerability) { create(:vulnerability, project: project) }
+
+      context 'when coming from the vulnerability itself' do
+        let_it_be(:todo) do
+          create(:todo, project: project, group: project.group, user: current_user, target: vulnerability)
+        end
+
+        it 'returns the work item web path' do
+          is_expected.to eq("http://localhost/#{project.full_path}/-/security/vulnerabilities/#{vulnerability.id}")
+        end
+      end
+
+      context 'when coming from a note on the vulnerability' do
+        let_it_be(:note) { create(:note, noteable: vulnerability, project: project) }
+        let_it_be(:todo) do
+          create(:todo, project: project, group: project.group, user: current_user, note: note, target: vulnerability)
+        end
+
+        it 'returns the work item web path with an anchor to the note' do
+          is_expected.to eq("http://localhost/#{project.full_path}/-/security/vulnerabilities/#{vulnerability.id}#note_#{note.id}")
+        end
+      end
+    end
   end
 end
diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb
index ef47c66e8b251c13344f7e1ef9d1737e5556bafe..1284dbe3394483eeb9d2ed4cc8754991223b8160 100644
--- a/spec/finders/todos_finder_spec.rb
+++ b/spec/finders/todos_finder_spec.rb
@@ -340,11 +340,12 @@
 
   describe '.todo_types' do
     it 'returns the expected types' do
+      shared_types = %w[Commit Issue WorkItem MergeRequest DesignManagement::Design AlertManagement::Alert Namespace Project]
       expected_result =
         if Gitlab.ee?
-          %w[Epic Commit Issue WorkItem MergeRequest DesignManagement::Design AlertManagement::Alert Namespace Project]
+          %w[Epic Vulnerability] + shared_types
         else
-          %w[Commit Issue WorkItem MergeRequest DesignManagement::Design AlertManagement::Alert Namespace Project]
+          shared_types
         end
 
       expect(described_class.todo_types).to contain_exactly(*expected_result)