CVE-2024-26145: Insufficient Information (NVD-CWE-noinfo)
value: Discourse Calendar adds the ability to create a dynamic calendar in the first post of a topic on Discourse. Uninvited users are able to gain access to private events by crafting a request to update their attendance. This problem is resolved in commit dfc4fa15f340189f177a1d1ab2cc94ffed3c1190. As a workaround, one may use post visibility to limit access.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-02-21T18:15Z
Repository: https://github.com/discourse/discourse-calendar
Language: Ruby
Files changed: app/controllers/discourse_post_event/invitees_controller.rb, spec/requests/invitees_controller_spec.rb
Commit date: 2024-02-21 15:36:36 +0800
Commit message: SECURITY: Disallow self invite to private events (#543)


Diff: diff --git a/app/controllers/discourse_post_event/invitees_controller.rb b/app/controllers/discourse_post_event/invitees_controller.rb
index 92958a06..39b636bf 100644
--- a/app/controllers/discourse_post_event/invitees_controller.rb
+++ b/app/controllers/discourse_post_event/invitees_controller.rb
@@ -33,10 +33,12 @@ module DiscoursePostEvent
 
     def create
       event = Event.find(params[:post_id])
       guardian.ensure_can_see!(event.post)
 
+      raise Discourse::InvalidAccess if !event.can_user_update_attendance(current_user)
+
       invitee =
         Invitee.create_attendance!(current_user.id, params[:post_id], invitee_params[:status])
       render json: InviteeSerializer.new(invitee)
     end
 
diff --git a/spec/requests/invitees_controller_spec.rb b/spec/requests/invitees_controller_spec.rb
index 07ebf440..d805b82f 100644
--- a/spec/requests/invitees_controller_spec.rb
+++ b/spec/requests/invitees_controller_spec.rb
@@ -171,11 +171,10 @@ module DiscoursePostEvent
 
         it "creates an invitee" do
           post "/discourse-post-event/events/#{post_event_2.id}/invitees.json",
                params: {
                  invitee: {
-                   user_id: user.id,
                    status: "not_going",
                  },
                }
 
           expect(Invitee).to exist(user_id: user.id, status: 2)
@@ -183,21 +182,38 @@ module DiscoursePostEvent
 
         it "sets tracking of the topic" do
           post "/discourse-post-event/events/#{post_event_2.id}/invitees.json",
                params: {
                  invitee: {
-                   user_id: user.id,
                    status: "going",
                  },
                }
 
           invitee = Invitee.find_by(user_id: user.id)
 
           tu = TopicUser.get(invitee.event.post.topic, user)
           expect(tu.notification_level).to eq(TopicUser.notification_levels[:watching])
         end
 
+        context "when someone is trying to invite themselves to a private event (creepy)" do
+          let(:post_event_2) { Fabricate(:event, post: post_1, status: "private") }
+          let(:other_user) { Fabricate(:user, username: "creep") }
+
+          before { sign_in(other_user) }
+
+          it "does not create an invitee" do
+            expect do
+              post "/discourse-post-event/events/#{post_event_2.id}/invitees.json",
+                   params: {
+                     invitee: {
+                       status: "going",
+                     },
+                   }
+            end.not_to change { post_event_2.invitees.count }
+          end
+        end
+
         context "when the invitee is the event owner" do
           let(:post_event_2) { Fabricate(:event, post: post_1) }
 
           it "creates an invitee" do
             expect(post_event_2.invitees.length).to eq(0)

Vulnerable code:                    user_id: user.id,
                   user_id: user.id,
Fixed code:       raise Discourse::InvalidAccess if !event.can_user_update_attendance(current_user)

        context "when someone is trying to invite themselves to a private event (creepy)" do
          let(:post_event_2) { Fabricate(:event, post: post_1, status: "private") }
          let(:other_user) { Fabricate(:user, username: "creep") }

          before { sign_in(other_user) }

          it "does not create an invitee" do
            expect do
              post "/discourse-post-event/events/#{post_event_2.id}/invitees.json",
                   params: {
                     invitee: {
                       status: "going",
                     },
                   }
            end.not_to change { post_event_2.invitees.count }
          end
        end