CVE-2022-31060 (published 2022-06-14T21:15Z)

Discourse is an open-source discussion platform. Prior to version 2.8.4 in the `stable` branch and version `2.9.0.beta5` in the `beta` and `tests-passed` branches, banner topic data is exposed on login-required sites. This issue is patched in version 2.8.4 in the `stable` branch and version `2.9.0.beta5` in the `beta` and `tests-passed` branches of Discourse. As a workaround, one may disable banners.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:P/I:N/A:N)
CVSS v3 base score: 5.3, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N)

Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/discourse/discourse
commit_details: repo_url: https://github.com/discourse/discourse
author: Blake Erickson
author_date: 2022-06-13 11:10:21-06:00
msg: SECURITY: banner-info (#17071)
repository: repo_url: https://github.com/discourse/discourse
repo_name: discourse/discourse
description: A platform for community discussion. Free, open, simple.
repo_language: Ruby
owner: discourse
file_changes: filename: application_controller.rb
change_type: ModificationType.MODIFY
diff: @@ -676,6 +676,7 @@ class ApplicationController < ActionController::Base
 
   def banner_json
     json = ApplicationController.banner_json_cache["json"]
+    return "{}" if !current_user && SiteSetting.login_required?
 
     unless json
       topic = Topic.where(archetype: Archetype.banner).first

programming_language: Ruby
filename: application_controller_spec.rb
change_type: ModificationType.MODIFY
diff: @@ -1002,4 +1002,53 @@ RSpec.describe ApplicationController do
       expect(response.status).to eq(200)
     end
   end
+
+  describe "#banner_json" do
+    let(:admin) { Fabricate(:admin) }
+    let(:user) { Fabricate(:user) }
+    fab!(:banner_topic) { Fabricate(:banner_topic) }
+    fab!(:p1) { Fabricate(:post, topic: banner_topic, raw: "A banner topic") }
+
+    before do
+      admin # to skip welcome wizard at home page `/`
+    end
+
+    context "login_required" do
+      before do
+        SiteSetting.login_required = true
+      end
+      it "does not include banner info for anonymous users" do
+        get "/login"
+
+        expect(response.body).to have_tag("div#data-preloaded") do |element|
+          json = JSON.parse(element.current_scope.attribute('data-preloaded').value)
+          expect(json['banner']).to eq("{}")
+        end
+      end
+
+      it "includes banner info for logged-in users" do
+        sign_in(user)
+        get "/"
+
+        expect(response.body).to have_tag("div#data-preloaded") do |element|
+          json = JSON.parse(element.current_scope.attribute('data-preloaded').value)
+          expect(JSON.parse(json['banner'])["html"]).to eq("<p>A banner topic</p>")
+        end
+      end
+    end
+
+    context "login not required" do
+      before do
+        SiteSetting.login_required = false
+      end
+      it "does include banner info for anonymous users" do
+        get "/login"
+
+        expect(response.body).to have_tag("div#data-preloaded") do |element|
+          json = JSON.parse(element.current_scope.attribute('data-preloaded').value)
+          expect(JSON.parse(json['banner'])["html"]).to eq("<p>A banner topic</p>")
+        end
+      end
+    end
+  end
 end

programming_language: Ruby