CVE-2022-21642: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: Discourse is an open source platform for community discussion. In affected versions when composing a message from topic the composer user suggestions reveals whisper participants. The issue has been patched in stable version 2.7.13 and beta version 2.8.0.beta11. There is no workaround for this issue and users are advised to upgrade.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
CVSS v3 base score: 4.3
Published: 2022-01-05T19:15Z
Repository: https://github.com/discourse/discourse
Language: Ruby
Files changed: app/models/user_search.rb, spec/models/user_search_spec.rb
Commit date: 2022-01-03 13:37:40 +0530
Commit message: SECURITY: only show user suggestions with regular post (#15436)


Diff: diff --git a/app/models/user_search.rb b/app/models/user_search.rb
index ba536535946..2b60c5c3e8e 100644
--- a/app/models/user_search.rb
+++ b/app/models/user_search.rb
@@ -81,11 +81,11 @@ class UserSearch
     return users.to_a if users.size >= @limit
 
     # 2. in topic
     if @topic_id
       in_topic = filtered_by_term_users
-        .where('users.id IN (SELECT user_id FROM posts WHERE topic_id = ?)', @topic_id)
+        .where('users.id IN (SELECT user_id FROM posts WHERE topic_id = ? AND post_type = ?)', @topic_id, Post.types[:regular])
 
       if @searching_user.present?
         in_topic = in_topic.where('users.id <> ?', @searching_user.id)
       end
 
diff --git a/spec/models/user_search_spec.rb b/spec/models/user_search_spec.rb
index e9d1a6ac3e5..ea011ac9209 100644
--- a/spec/models/user_search_spec.rb
+++ b/spec/models/user_search_spec.rb
@@ -112,10 +112,11 @@ describe UserSearch do
     fab!(:post3) { Fabricate :post, user: mr_orange, topic: topic }
     fab!(:post4) { Fabricate :post, user: mr_pink, topic: topic }
     fab!(:post5) { Fabricate :post, user: mr_brown, topic: topic3 }
     fab!(:post6) { Fabricate :post, user: mr_white, topic: topic }
     fab!(:post7) { Fabricate :post, user: staged, topic: topic4 }
+    fab!(:post8) { Fabricate :post, user: mr_brown, topic: topic2, post_type: Post.types[:whisper] }
 
     before { mr_white.update(suspended_at: 1.day.ago, suspended_till: 1.year.from_now) }
 
     it "can search by name and username" do
       # normal search
@@ -168,10 +169,15 @@ describe UserSearch do
 
       results = search_for(mr_b.username, topic_id: topic3.id)
       expect(results).to eq [mr_b, mr_brown, mr_blue].map(&:username)
     end
 
+    it "does not reveal whisper users" do
+      results = search_for("", topic_id: topic2.id)
+      expect(results).to eq [mr_blue.username]
+    end
+
     it "only reveals topic participants to people with permission" do
       pm_topic = Fabricate(:private_message_post).topic
 
       # Anonymous, does not have access
       expect do

Vulnerable code:         .where('users.id IN (SELECT user_id FROM posts WHERE topic_id = ?)', @topic_id)
Fixed code:         .where('users.id IN (SELECT user_id FROM posts WHERE topic_id = ? AND post_type = ?)', @topic_id, Post.types[:regular])
    fab!(:post8) { Fabricate :post, user: mr_brown, topic: topic2, post_type: Post.types[:whisper] }
    it "does not reveal whisper users" do
      results = search_for("", topic_id: topic2.id)
      expect(results).to eq [mr_blue.username]
    end