CVE-2024-38368 (published 2024-07-01T21:15Z)

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.


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/CocoaPods/trunk.cocoapods.org
commit_details: repo_url: https://github.com/CocoaPods/trunk.cocoapods.org
author: Orta Therox
author_date: 2023-09-22 07:40:00-04:00
msg: Drop the claims feature
repository: repo_url: https://github.com/CocoaPods/trunk.cocoapods.org
repo_name: CocoaPods/trunk.cocoapods.org
description: The authentication server for CocoaPods push
repo_language: Ruby
owner: CocoaPods
file_changes: filename: claims_controller.rb
change_type: ModificationType.MODIFY
diff: @@ -25,40 +25,7 @@ module Pod
       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 ------------------------------------------------------------------------------
 
@@ -111,10 +78,6 @@ module Pod
         !@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?
@@ -123,24 +86,6 @@ module Pod
           @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

programming_language: Ruby
filename: thanks.slim
change_type: ModificationType.MODIFY
diff: @@ -9,7 +9,7 @@ ruby:
 
   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>.

programming_language: Ruby
filename: claims_controller_spec.rb
change_type: ModificationType.MODIFY
diff: @@ -1,126 +1,7 @@
 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')

programming_language: Ruby