CVE-2024-38368: Insufficient Information (NVD-CWE-noinfo)
value: trunk.cocoapods.org is the authentication server for the CoacoaPods dependency manager. A vulnerability affected older pods which migrated from the pre-2014 pull request workflow to trunk. If the pods had never been claimed then it was still possible to do so. It was also possible to have all owners removed from a pod, and that made the pod available for the same claiming system. This was patched server-side in commit 71be5440906b6bdfbc0bcc7f8a9fec33367ea0f4 in September 2023.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-07-01T21:15Z
Repository: https://github.com/CocoaPods/trunk.cocoapods.org
Language: Ruby
Files changed: app/controllers/claims_controller.rb, app/views/claims/thanks.slim, spec/functional/claims_controller_spec.rb
Commit date: 2023-09-22 07:40:00 -0400
Commit message: Drop the claims feature

Diff: diff --git a/app/controllers/claims_controller.rb b/app/controllers/claims_controller.rb
index 94badd7..f205f28 100644
--- a/app/controllers/claims_controller.rb
+++ b/app/controllers/claims_controller.rb
@@ -23,44 +23,11 @@ module Pod
           combined << Slim::Template.new("shared/includes/_#{source}.slim", {}).render
         end.join
       end
 
       # --- Claims --------------------------------------------------------------------------------
-
-      get '/new' do
-        @owner = Owner.new
-        @pods = []
-        slim :new
-      end
-
-      post '/' do
-        find_owner
-        find_pods
-        if @owner.valid? && valid_pods?
-          change_ownership
-          if all_pods_already_claimed?
-            query = {
-              :claimer_email => @owner.email,
-              :pods => @already_claimed_pods,
-            }
-            redirect to("/disputes/new?#{query.to_query}")
-          else
-            query = {
-              :claimer_email => @owner.email,
-              :successfully_claimed => @successfully_claimed_pods,
-              :already_claimed => @already_claimed_pods,
-            }
-            redirect to("/thanks?#{query.to_query}")
-          end
-        end
-        prepare_errors
-        slim :new
-      end
-
-      get '/thanks' do
-        slim :thanks
-      end
+      #  Deprecated
 
       # --- Disputes ------------------------------------------------------------------------------
 
       get '/disputes/new' do
         @pods = params[:pods].map { |name| Pod.find_by_name(name) }
@@ -109,38 +76,16 @@ module Pod
 
       def valid_pods?
         !@pods.empty? && @invalid_pods.empty?
       end
 
-      def all_pods_already_claimed?
-        @successfully_claimed_pods.empty? && !@already_claimed_pods.empty?
-      end
-
       def prepare_errors
         @errors = @owner.errors.full_messages.map { |message| "Owner #{message}." }
         if !@invalid_pods.empty?
           @errors << "Unknown #{'Pod'.pluralize(@invalid_pods.size)} #{@invalid_pods.to_sentence}."
         elsif @pods.empty?
           @errors << 'No Pods specified.'
         end
       end
-
-      def change_ownership
-        @successfully_claimed_pods = []
-        @already_claimed_pods = []
-        DB.test_safe_transaction do
-          @owner.save_changes(:raise_on_save_failure => true)
-          unclaimed_owner = Owner.unclaimed
-          @pods.each do |pod|
-            if pod.owners == [unclaimed_owner]
-              @owner.add_pod(pod)
-              pod.remove_owner(unclaimed_owner)
-              @successfully_claimed_pods << pod.name
-            else
-              @already_claimed_pods << pod.name
-            end
-          end
-        end
-      end
     end
   end
 end
diff --git a/app/views/claims/thanks.slim b/app/views/claims/thanks.slim
index 17c7351..b34bfa0 100644
--- a/app/views/claims/thanks.slim
+++ b/app/views/claims/thanks.slim
@@ -7,9 +7,9 @@ ruby:
 
   p If you have any co-maintainers, you can now add them as ‘owners’ as well. For information on how to do this see the <a href = "http://guides.cocoapods.org/making/getting-setup-with-trunk">getting started with Trunk</a> guide.
 
   p Once we have finished the transition period, you will be able to push new versions of #{params[:successfully_claimed].size == 1 ? 'these pods' : 'this pod'} directly from the command-line. For more details see the <a href = "http://guides.cocoapods.org/making/getting-setup-with-trunk">getting started with Trunk</a> guide.
 - else
-  p All of your choosen Pods are already claimed.
+  p All of your chosen Pods are already claimed.
 
 - unless params[:already_claimed] == [''] || params[:already_claimed] == nil
   p The following #{params[:already_claimed].size == 1 ? 'pod has' : 'pods have'} already been claimed: #{params[:already_claimed].to_sentence}. If you disagree with this please <a href="#{url("/disputes/new?#{{ :claimer_email => params[:claimer_email], :pods => params[:already_claimed] }.to_query}")}">file a dispute</a>.
diff --git a/spec/functional/claims_controller_spec.rb b/spec/functional/claims_controller_spec.rb
index f100eeb..2f317d6 100644
--- a/spec/functional/claims_controller_spec.rb
+++ b/spec/functional/claims_controller_spec.rb
@@ -1,128 +1,9 @@
 require File.expand_path('../spec_helper', __dir__)
 
 module Pod::TrunkApp
-  describe ClaimsController, 'when claiming pods' do
-    seed_unclaimed
-
-    it 'renders a new claim form' do
-      get '/new'
-      last_response.status.should == 200
-      form = response_doc.css('form').first
-      form['action'].should == '/claims'
-      form['method'].should == 'POST'
-    end
-
-    it 'does not create an owner if no pods are specified' do
-      lambda do
-        post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' }, :pods => []
-      end.should.not.change { Owner.count }
-      last_response.status.should == 200
-      form = response_doc.css('form').first
-      form.css('input[name="owner[email]"]').first['value'].should == 'appie@example.com'
-      form.css('input[name="owner[name]"]').first['value'].should == 'Appie Duran'
-    end
-
-    before do
-      @pod = Owner.unclaimed.add_pod(:name => 'AFNetworking')
-    end
-
-    it 'creates an owner and assigns it to the claimed pods' do
-      lambda do
-        post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' }, :pods => ['AFNetworking']
-      end.should.change { Owner.count }
-      owner = Owner.find_by_email('appie@example.com')
-      owner.name.should == 'Appie Duran'
-      @pod.reload.owners.should == [owner]
-    end
-
-    it 'finds an existing owner and assigns it to the claimed pods' do
-      owner = Owner.create(:email => 'appie@example.com', :name => 'Appie Duran')
-      lambda do
-        post '/', :owner => { :email => 'appie@example.com' }, :pods => ['AFNetworking']
-      end.should.not.change { Owner.count }
-      @pod.reload.owners.should == [owner]
-    end
-
-    it "finds an existing owner and doesn't update its name" do
-      owner = Owner.create(:email => 'appie@example.com', :name => 'Appie Duran')
-      post '/', :owner => { :email => 'appie@example.com', :name => 'Appiepocalypse' }, :pods => ['AFNetworking']
-      owner.reload.name.should == 'Appie Duran'
-    end
-
-    it 'does not assign a pod that has already been claimed' do
-      other_pod = Pod.create(:name => 'ObjectiveSugar')
-      other_owner = Owner.create(:email => 'jenny@example.com', :name => 'Jenny Penny')
-      other_owner.add_pod(other_pod)
-      post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' },
-                :pods => %w[AFNetworking ObjectiveSugar]
-      owner = Owner.find_by_email('appie@example.com')
-      @pod.reload.owners.should == [owner]
-      other_pod.reload.owners.should == [other_owner]
-      last_response.status.should == 302
-      query = { :claimer_email => owner.email, :successfully_claimed => ['AFNetworking'],
-                :already_claimed => ['ObjectiveSugar'] }
-      last_response.location.should == "https://example.org/thanks?#{query.to_query}"
-    end
-
-    it 'immediately redirects to the dispute page if all pods are claimed' do
-      @pod.remove_owner(Owner.unclaimed)
-      owner = Owner.create(:email => 'jenny@example.com', :name => 'Jenny Penny')
-      owner.add_pod(@pod)
-      lambda do
-        post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' }, :pods => ['AFNetworking']
-      end.should.change { Owner.count }
-      last_response.status.should == 302
-      uri = URI.parse(last_response.location)
-      uri.path.should == '/disputes/new'
-      query = { 'claimer_email' => 'appie@example.com', 'pods[]' => 'AFNetworking' }
-      Rack::Utils.parse_query(uri.query).should == query
-      Owner.find_by_email('appie@example.com').should.not.be.nil
-    end
-
-    it 'rolls back in case of an error' do
-      Pod.any_instance.stubs(:remove_owner).raises
-      lambda do
-        should.raise do
-          post('/',
-               :owner => {
-                 :email => 'appie@example.com',
-                 :name => 'Appie Duran',
-               },
-               :pods => ['AFNetworking'])
-        end
-      end.should.not.change { Owner.count }
-      @pod.reload.owners.should == [Owner.unclaimed]
-    end
-
-    it 'shows validation errors' do
-      post('/',
-           :owner => { :email => 'appie@example.com', :name => '' },
-           :pods => %w[AFNetworking EYFNetworking JAYSONKit])
-      last_response.status.should == 200
-      @pod.reload.owners.should == [Owner.unclaimed]
-      errors = response_doc.css('.errors li')
-      errors.first.text.should == 'Owner name is not present.'
-      errors.last.text.should == 'Unknown Pods EYFNetworking and JAYSONKit.'
-    end
-
-    it 'shows a thanks page' do
-      get('/thanks',
-          :claimer_email => 'appie@example.com',
-          :successfully_claimed => ['AFNetworking'],
-          :already_claimed => ['JSONKit'])
-      last_response.status.should == 200
-      last_response.body.should.include 'AFNetworking'
-      last_response.body.should.include 'JSONKit'
-
-      link = response_doc.css('article p a')[2]
-      query = { :claimer_email => 'appie@example.com', :pods => ['JSONKit'] }
-      link['href'].should == "https://example.org/disputes/new?#{query.to_query}"
-    end
-  end
-
-  describe ClaimsController, 'concerning disputes' do
+    describe ClaimsController, 'concerning disputes' do
     before do
       @owner = Owner.create(:email => 'jenny@example.com', :name => 'Jenny Penny')
       @pod = @owner.add_pod(:name => 'AFNetworking')
     end
 

Vulnerable code: 
      get '/new' do
        @owner = Owner.new
        @pods = []
        slim :new
      end

      post '/' do
        find_owner
        find_pods
        if @owner.valid? && valid_pods?
          change_ownership
          if all_pods_already_claimed?
            query = {
              :claimer_email => @owner.email,
              :pods => @already_claimed_pods,
            }
            redirect to("/disputes/new?#{query.to_query}")
          else
            query = {
              :claimer_email => @owner.email,
              :successfully_claimed => @successfully_claimed_pods,
              :already_claimed => @already_claimed_pods,
            }
            redirect to("/thanks?#{query.to_query}")
          end
        end
        prepare_errors
        slim :new
      end

      get '/thanks' do
        slim :thanks
      end
      def all_pods_already_claimed?
        @successfully_claimed_pods.empty? && !@already_claimed_pods.empty?
      end


      def change_ownership
        @successfully_claimed_pods = []
        @already_claimed_pods = []
        DB.test_safe_transaction do
          @owner.save_changes(:raise_on_save_failure => true)
          unclaimed_owner = Owner.unclaimed
          @pods.each do |pod|
            if pod.owners == [unclaimed_owner]
              @owner.add_pod(pod)
              pod.remove_owner(unclaimed_owner)
              @successfully_claimed_pods << pod.name
            else
              @already_claimed_pods << pod.name
            end
          end
        end
      end
  p All of your choosen Pods are already claimed.
  describe ClaimsController, 'when claiming pods' do
    seed_unclaimed

    it 'renders a new claim form' do
      get '/new'
      last_response.status.should == 200
      form = response_doc.css('form').first
      form['action'].should == '/claims'
      form['method'].should == 'POST'
    end

    it 'does not create an owner if no pods are specified' do
      lambda do
        post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' }, :pods => []
      end.should.not.change { Owner.count }
      last_response.status.should == 200
      form = response_doc.css('form').first
      form.css('input[name="owner[email]"]').first['value'].should == 'appie@example.com'
      form.css('input[name="owner[name]"]').first['value'].should == 'Appie Duran'
    end

    before do
      @pod = Owner.unclaimed.add_pod(:name => 'AFNetworking')
    end

    it 'creates an owner and assigns it to the claimed pods' do
      lambda do
        post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' }, :pods => ['AFNetworking']
      end.should.change { Owner.count }
      owner = Owner.find_by_email('appie@example.com')
      owner.name.should == 'Appie Duran'
      @pod.reload.owners.should == [owner]
    end

    it 'finds an existing owner and assigns it to the claimed pods' do
      owner = Owner.create(:email => 'appie@example.com', :name => 'Appie Duran')
      lambda do
        post '/', :owner => { :email => 'appie@example.com' }, :pods => ['AFNetworking']
      end.should.not.change { Owner.count }
      @pod.reload.owners.should == [owner]
    end

    it "finds an existing owner and doesn't update its name" do
      owner = Owner.create(:email => 'appie@example.com', :name => 'Appie Duran')
      post '/', :owner => { :email => 'appie@example.com', :name => 'Appiepocalypse' }, :pods => ['AFNetworking']
      owner.reload.name.should == 'Appie Duran'
    end

    it 'does not assign a pod that has already been claimed' do
      other_pod = Pod.create(:name => 'ObjectiveSugar')
      other_owner = Owner.create(:email => 'jenny@example.com', :name => 'Jenny Penny')
      other_owner.add_pod(other_pod)
      post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' },
                :pods => %w[AFNetworking ObjectiveSugar]
      owner = Owner.find_by_email('appie@example.com')
      @pod.reload.owners.should == [owner]
      other_pod.reload.owners.should == [other_owner]
      last_response.status.should == 302
      query = { :claimer_email => owner.email, :successfully_claimed => ['AFNetworking'],
                :already_claimed => ['ObjectiveSugar'] }
      last_response.location.should == "https://example.org/thanks?#{query.to_query}"
    end

    it 'immediately redirects to the dispute page if all pods are claimed' do
      @pod.remove_owner(Owner.unclaimed)
      owner = Owner.create(:email => 'jenny@example.com', :name => 'Jenny Penny')
      owner.add_pod(@pod)
      lambda do
        post '/', :owner => { :email => 'appie@example.com', :name => 'Appie Duran' }, :pods => ['AFNetworking']
      end.should.change { Owner.count }
      last_response.status.should == 302
      uri = URI.parse(last_response.location)
      uri.path.should == '/disputes/new'
      query = { 'claimer_email' => 'appie@example.com', 'pods[]' => 'AFNetworking' }
      Rack::Utils.parse_query(uri.query).should == query
      Owner.find_by_email('appie@example.com').should.not.be.nil
    end

    it 'rolls back in case of an error' do
      Pod.any_instance.stubs(:remove_owner).raises
      lambda do
        should.raise do
          post('/',
               :owner => {
                 :email => 'appie@example.com',
                 :name => 'Appie Duran',
               },
               :pods => ['AFNetworking'])
        end
      end.should.not.change { Owner.count }
      @pod.reload.owners.should == [Owner.unclaimed]
    end

    it 'shows validation errors' do
      post('/',
           :owner => { :email => 'appie@example.com', :name => '' },
           :pods => %w[AFNetworking EYFNetworking JAYSONKit])
      last_response.status.should == 200
      @pod.reload.owners.should == [Owner.unclaimed]
      errors = response_doc.css('.errors li')
      errors.first.text.should == 'Owner name is not present.'
      errors.last.text.should == 'Unknown Pods EYFNetworking and JAYSONKit.'
    end

    it 'shows a thanks page' do
      get('/thanks',
          :claimer_email => 'appie@example.com',
          :successfully_claimed => ['AFNetworking'],
          :already_claimed => ['JSONKit'])
      last_response.status.should == 200
      last_response.body.should.include 'AFNetworking'
      last_response.body.should.include 'JSONKit'

      link = response_doc.css('article p a')[2]
      query = { :claimer_email => 'appie@example.com', :pods => ['JSONKit'] }
      link['href'].should == "https://example.org/disputes/new?#{query.to_query}"
    end
  end

  describe ClaimsController, 'concerning disputes' do
Fixed code:       #  Deprecated
  p All of your chosen Pods are already claimed.
    describe ClaimsController, 'concerning disputes' do