diff --git a/ee/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb b/ee/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
index b4312c0c1400034fb382f03b22f17633e819d8e1..4f7ed7b3611042adb4015489f00c2af5741e64ad 100644
--- a/ee/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
+++ b/ee/lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb
@@ -9,8 +9,8 @@ module Gitlab
 
           attr_reader :base_report, :head_report
 
-          def initialize(base_report, head_report)
-            @base_report = base_report || []
+          def initialize(base_report = [], head_report = [])
+            @base_report = base_report
             @head_report = head_report
           end
 
@@ -28,7 +28,8 @@ module Gitlab
 
           def existing
             strong_memoize(:existing) do
-              base_report & head_report
+              # Existing vulnerabilities should point to source report for most recent information
+              head_report & base_report
             end
           end
         end
diff --git a/ee/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb b/ee/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..02b5fd1d4a87ab9c164f229d58b2d8c33f0cd97a
--- /dev/null
+++ b/ee/spec/lib/gitlab/ci/reports/security/vulnerability_reports_comparer_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Ci::Reports::Security::VulnerabilityReportsComparer do
+  let!(:identifier) { create(:vulnerabilities_identifier) }
+  let!(:base_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '123') }
+  let!(:head_vulnerability) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '123') }
+
+  before do
+    allow(base_vulnerability).to receive(:location).and_return({})
+    allow(head_vulnerability).to receive(:location).and_return({})
+  end
+
+  describe '#existing' do
+    context 'with existing reports' do
+      let(:comparer) { described_class.new([base_vulnerability], [head_vulnerability]) }
+
+      it 'points to source tree' do
+        allow(head_vulnerability).to receive(:raw_metadata).and_return('')
+
+        expect(comparer.existing.count).to eq(1)
+        expect(comparer.existing).to eq([head_vulnerability])
+      end
+    end
+  end
+
+  describe '#added' do
+    let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888') }
+
+    context 'with new vulnerability' do
+      let(:comparer) { described_class.new([base_vulnerability], [head_vulnerability, vuln]) }
+
+      it 'points to source tree' do
+        expect(comparer.added.count).to eq(1)
+        expect(comparer.added).to eq([vuln])
+      end
+    end
+  end
+
+  describe '#fixed' do
+    let(:vuln) { build(:vulnerabilities_occurrence, report_type: :sast, identifiers: [identifier], location_fingerprint: '888') }
+
+    context 'with fixed vulnerability' do
+      let(:comparer) { described_class.new([base_vulnerability, vuln], [head_vulnerability]) }
+
+      it 'points to base tree' do
+        expect(comparer.fixed.count).to eq(1)
+        expect(comparer.fixed).to eq([vuln])
+      end
+    end
+  end
+
+  describe 'with empty vulnerabilities' do
+    let(:comparer) { described_class.new }
+
+    it 'returns empty array when reports are not present' do
+      expect(comparer.existing).to be_empty
+      expect(comparer.fixed).to be_empty
+      expect(comparer.added).to be_empty
+    end
+  end
+end