diff --git a/danger/plugins/todos.rb b/danger/plugins/todos.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b31f147f2af28117cbe20617f37d2efa19a4d0a8
--- /dev/null
+++ b/danger/plugins/todos.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/outdated_todo'
+
+module Danger
+  class Todos < ::Danger::Plugin
+    def check_outdated_todos(filenames)
+      Tooling::Danger::OutdatedTodo.new(filenames, context: self).check
+    end
+  end
+end
diff --git a/danger/todos/Dangerfile b/danger/todos/Dangerfile
new file mode 100644
index 0000000000000000000000000000000000000000..45494e59bacfabb773d614390300bf64a4ce1b49
--- /dev/null
+++ b/danger/todos/Dangerfile
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+todos.check_outdated_todos(git.deleted_files)
diff --git a/spec/fixtures/tooling/danger/rubocop_todo/cop1.yml b/spec/fixtures/tooling/danger/rubocop_todo/cop1.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8f240b926823a8ecf7b21639b1c2bca6746e1186
--- /dev/null
+++ b/spec/fixtures/tooling/danger/rubocop_todo/cop1.yml
@@ -0,0 +1,5 @@
+---
+Cop1:
+  Exclude:
+    - 'app/controllers/application_controller.rb'
+    - 'app/controllers/acme_challenges_controller.rb'
diff --git a/spec/fixtures/tooling/danger/rubocop_todo/cop2.yml b/spec/fixtures/tooling/danger/rubocop_todo/cop2.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9ab2c0dabb9b91e8f3fe4ce99558e1b9ae41aa5c
--- /dev/null
+++ b/spec/fixtures/tooling/danger/rubocop_todo/cop2.yml
@@ -0,0 +1,4 @@
+---
+Cop2:
+  Exclude:
+    - 'app/controllers/application_controller.rb'
diff --git a/spec/tooling/danger/outdated_todo_spec.rb b/spec/tooling/danger/outdated_todo_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3a3909c69ac2cab28b90579041a644a2d84d2828
--- /dev/null
+++ b/spec/tooling/danger/outdated_todo_spec.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../tooling/danger/outdated_todo'
+
+RSpec.describe Tooling::Danger::OutdatedTodo, feature_category: :tooling do
+  let(:fake_danger) { double }
+  let(:filenames) { ['app/controllers/application_controller.rb'] }
+
+  let(:todos) do
+    [
+      File.join('spec', 'fixtures', 'tooling', 'danger', 'rubocop_todo', '**', '*.yml')
+    ]
+  end
+
+  subject(:plugin) { described_class.new(filenames, context: fake_danger, todos: todos) }
+
+  context 'when the filenames are mentioned in single todo' do
+    let(:filenames) { ['app/controllers/acme_challenges_controller.rb'] }
+
+    it 'warns about mentions' do
+      expect(fake_danger)
+        .to receive(:warn)
+        .with <<~MESSAGE
+          `app/controllers/acme_challenges_controller.rb` was removed but is mentioned in:
+          - `spec/fixtures/tooling/danger/rubocop_todo/cop1.yml:5`
+        MESSAGE
+
+      plugin.check
+    end
+  end
+
+  context 'when the filenames are mentioned in multiple todos' do
+    let(:filenames) do
+      [
+        'app/controllers/application_controller.rb',
+        'app/controllers/acme_challenges_controller.rb'
+      ]
+    end
+
+    it 'warns about mentions' do
+      expect(fake_danger)
+        .to receive(:warn)
+        .with(<<~FIRSTMESSAGE)
+          `app/controllers/application_controller.rb` was removed but is mentioned in:
+          - `spec/fixtures/tooling/danger/rubocop_todo/cop1.yml:4`
+          - `spec/fixtures/tooling/danger/rubocop_todo/cop2.yml:4`
+        FIRSTMESSAGE
+
+      expect(fake_danger)
+        .to receive(:warn)
+        .with(<<~SECONDMESSAGE)
+          `app/controllers/acme_challenges_controller.rb` was removed but is mentioned in:
+          - `spec/fixtures/tooling/danger/rubocop_todo/cop1.yml:5`
+        SECONDMESSAGE
+
+      plugin.check
+    end
+  end
+
+  context 'when the filenames are not mentioned in todos' do
+    let(:filenames) { ['any/inexisting/file.rb'] }
+
+    it 'does not warn' do
+      expect(fake_danger).not_to receive(:warn)
+
+      plugin.check
+    end
+  end
+
+  context 'when there is no todos' do
+    let(:filenames) { ['app/controllers/acme_challenges_controller.rb'] }
+    let(:todos) { [] }
+
+    it 'does not warn' do
+      expect(fake_danger).not_to receive(:warn)
+
+      plugin.check
+    end
+  end
+end
diff --git a/tooling/danger/outdated_todo.rb b/tooling/danger/outdated_todo.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a5f5cc897a9ae4f7914ca74d6ef886cb9c02177e
--- /dev/null
+++ b/tooling/danger/outdated_todo.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Tooling
+  module Danger
+    class OutdatedTodo
+      TODOS_GLOBS = %w[
+        .rubocop_todo/**/*.yml
+        spec/support/rspec_order_todo.yml
+      ].freeze
+
+      def initialize(filenames, context:, todos: TODOS_GLOBS)
+        @filenames = filenames
+        @context = context
+        @todos_globs = todos
+      end
+
+      def check
+        filenames.each do |filename|
+          check_filename(filename)
+        end
+      end
+
+      private
+
+      attr_reader :filenames, :context
+
+      def check_filename(filename)
+        mentions = all_mentions_for(filename)
+
+        return if mentions.empty?
+
+        context.warn <<~MESSAGE
+          `#{filename}` was removed but is mentioned in:
+          #{mentions.join("\n")}
+        MESSAGE
+      end
+
+      def all_mentions_for(filename)
+        todos
+          .filter_map { |todo| mentioned_lines(filename, todo) }
+          .flatten
+          .map { |todo| "- `#{todo}`" }
+      end
+
+      def mentioned_lines(filename, todo)
+        File
+          .foreach(todo)
+          .with_index(1)
+          .select { |text, _line| text.match?(/.*#{filename}.*/) }
+          .map { |_text, line| "#{todo}:#{line}" }
+      end
+
+      def todos
+        @todos ||= @todos_globs.flat_map { |value| Dir.glob(value) }
+      end
+    end
+  end
+end