CVE-2022-23546: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: In version 2.9.0.beta14 of Discourse, an open-source discussion platform, maliciously embedded urls can leak an admin's digest of recent topics, possibly exposing private information. A patch is available for version 2.9.0.beta15. There are no known workarounds for this issue.
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: 5.5
Published: 2023-01-05T19:15Z
Repository: https://github.com/discourse/discourse
Language: Ruby
Files changed: app/assets/javascripts/admin/addon/models/email-preview.js, config/routes.rb, spec/requests/admin/email_controller_spec.rb
Commit date: 2023-01-05 06:57:12 +0800
Commit message: SECURITY: Convert send_digest to a post request (#19746)

Co-authored-by: Isaac Janzen <isaac.janzen@discourse.org>
Diff: diff --git a/app/assets/javascripts/admin/addon/models/email-preview.js b/app/assets/javascripts/admin/addon/models/email-preview.js
index 96ffe2f94994..1a709db82bba 100644
--- a/app/assets/javascripts/admin/addon/models/email-preview.js
+++ b/app/assets/javascripts/admin/addon/models/email-preview.js
@@ -14,10 +14,11 @@ EmailPreview.reopenClass({
     }).then((result) => EmailPreview.create(result));
   },
 
   sendDigest(username, lastSeenAt, email) {
     return ajax("/admin/email/send-digest.json", {
+      type: "POST",
       data: { last_seen_at: lastSeenAt || oneWeekAgo(), username, email },
     });
   },
 });
 
diff --git a/config/routes.rb b/config/routes.rb
index a60b48146bee..baf501a6f986 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -175,11 +175,11 @@ Discourse::Application.routes.draw do
           get "rejected"
           get "/incoming/:id/raw" => "email#raw_email"
           get "/incoming/:id" => "email#incoming"
           get "/incoming_from_bounced/:id" => "email#incoming_from_bounced"
           get "preview-digest" => "email#preview_digest"
-          get "send-digest" => "email#send_digest"
+          post "send-digest" => "email#send_digest"
           get "smtp_should_reject"
           post "handle_mail"
           get "advanced-test"
           post "advanced-test" => "email#advanced_test"
         end
diff --git a/spec/requests/admin/email_controller_spec.rb b/spec/requests/admin/email_controller_spec.rb
index 0f0b7acdf9e9..9932fa44369c 100644
--- a/spec/requests/admin/email_controller_spec.rb
+++ b/spec/requests/admin/email_controller_spec.rb
@@ -335,10 +335,23 @@ RSpec.describe Admin::EmailController do
 
       include_examples "preview digest inaccessible"
     end
   end
 
+  describe '#send_digest' do
+    context "when logged in as an admin" do
+      before { sign_in(admin) }
+
+      it "sends the digest" do
+        post "/admin/email/send-digest.json", params: {
+          last_seen_at: 1.week.ago, username: admin.username, email: email('previous_replies')
+        }
+        expect(response.status).to eq(200)
+      end
+    end
+  end
+
   describe '#handle_mail' do
     context "when logged in as an admin" do
       before { sign_in(admin) }
 
       it "returns a bad request if neither email parameter is present" do

Vulnerable code:           get "send-digest" => "email#send_digest"
Fixed code:       type: "POST",
          post "send-digest" => "email#send_digest"
  describe '#send_digest' do
    context "when logged in as an admin" do
      before { sign_in(admin) }

      it "sends the digest" do
        post "/admin/email/send-digest.json", params: {
          last_seen_at: 1.week.ago, username: admin.username, email: email('previous_replies')
        }
        expect(response.status).to eq(200)
      end
    end
  end