CVE-2024-27085 (published 2024-03-15T20:15Z)

Discourse is an open source platform for community discussion. In affected versions users that are allowed to invite others can inject arbitrarily large data in parameters used in the invite route. The problem has been patched in the latest version of Discourse. Users are advised to upgrade. Users unable to upgrade should disable invites or restrict access to them using the `invite allowed groups` site setting. 


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: Penar Musaraj
author_date: 2024-02-19 16:34:40-05:00
msg: SECURITY: Limit invites params length
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: invite.rb
change_type: ModificationType.MODIFY
diff: @@ -32,8 +32,9 @@ class Invite < ActiveRecord::Base
   has_many :topics, through: :topic_invites, source: :topic
 
   validates_presence_of :invited_by_id
-  validates :email, email: true, allow_blank: true
+  validates :email, email: true, allow_blank: true, length: { maximum: 500 }
   validates :custom_message, length: { maximum: 1000 }
+  validates :domain, length: { maximum: 500 }
   validate :ensure_max_redemptions_allowed
   validate :valid_redemption_count
   validate :valid_domain, if: :will_save_change_to_domain?
@@ -350,7 +351,7 @@ class Invite < ActiveRecord::Base
     self.domain.downcase!
 
     if self.domain !~ Invite::DOMAIN_REGEX
-      self.errors.add(:base, I18n.t("invite.domain_not_allowed"))
+      self.errors.add(:base, I18n.t("invite.domain_not_allowed_admin"))
     end
   end
 

programming_language: Ruby
filename: server.en.yml
change_type: ModificationType.MODIFY
diff: @@ -342,6 +342,7 @@ en:
     requires_groups: "Invite was not saved because the specified topic is inaccessible. Add one of the following groups: %{groups}."
     max_invite_emails_limit_exceeded: "Request failed because number of emails exceeded the maximum (%{max})."
     domain_not_allowed: "Your email cannot be used to redeem this invite."
+    domain_not_allowed_admin: "This domain cannot be used for invites."
     max_redemptions_allowed_one: "for email invites should be 1."
     redemption_count_less_than_max: "should be less than %{max_redemptions_allowed}."
     email_xor_domain: "Email and domain fields are not allowed at the same time"

programming_language: Python
filename: invites_controller_spec.rb
change_type: ModificationType.MODIFY
diff: @@ -433,6 +433,18 @@ RSpec.describe InvitesController do
         end
       end
 
+      context "when email address is too long" do
+        let(:email) { "a" * 495 + "@example.com" }
+
+        it "fails" do
+          create_invite
+          expect(response).to have_http_status :unprocessable_entity
+          expect(response.parsed_body["errors"]).to be_present
+          error_message = response.parsed_body["errors"].first
+          expect(error_message).to eq("Email is too long (maximum is 500 characters)")
+        end
+      end
+
       context "when providing an email belonging to an existing user" do
         let(:email) { user.email }
 
@@ -460,6 +472,46 @@ RSpec.describe InvitesController do
       end
     end
 
+    context "with domain invite" do
+      it "works" do
+        sign_in(admin)
+
+        post "/invites.json", params: { domain: "example.com" }
+        expect(response).to have_http_status :ok
+      end
+
+      it "fails when domain is invalid" do
+        sign_in(admin)
+
+        post "/invites.json", params: { domain: "example" }
+
+        expect(response).to have_http_status :unprocessable_entity
+
+        error_message = response.parsed_body["errors"].first
+        expect(error_message).to eq(I18n.t("invite.domain_not_allowed_admin"))
+      end
+
+      it "fails when domain is too long" do
+        sign_in(admin)
+
+        post "/invites.json", params: { domain: "a" * 500 + ".ca" }
+        expect(response).to have_http_status :unprocessable_entity
+
+        error_message = response.parsed_body["errors"].first
+        expect(error_message).to eq("Domain is too long (maximum is 500 characters)")
+      end
+
+      it "fails when custom message is too long" do
+        sign_in(admin)
+
+        post "/invites.json", params: { custom_message: "b" * 1001, domain: "example.com" }
+        expect(response).to have_http_status :unprocessable_entity
+
+        error_message = response.parsed_body["errors"].first
+        expect(error_message).to eq("Custom message is too long (maximum is 1000 characters)")
+      end
+    end
+
     context "with link invite" do
       it "works" do
         sign_in(admin)

programming_language: Ruby