CVE-2020-36190 (Ruby, published 2021-01-12T20:15Z)
Description: value: RailsAdmin (aka rails_admin) before 1.4.3 and 2.x before 2.0.2 allows XSS via nested forms.
Severity: MEDIUM (CVSS v3 base score: 6.1)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/sferik/rails_admin
Files changed:
app/assets/javascripts/rails_admin/ra.nested-form-hooks.js
app/assets/javascripts/rails_admin/ra.widgets.js
spec/integration/fields/has_many_association_spec.rb
spec/integration/fields/has_one_association_spec.rb
Commit message: Fix XSS vulnerability in nested forms


Vulnerable code:
    new_tab = $('<li><a data-toggle="tab" href="#' + field.attr('id') + '">' + field.children('.object-infos').data('object-label') + '</a></li>');
      controls.find('.add_nested_fields').removeClass('add_nested_fields').html(field.children('.object-infos').data('object-label'));
          nav.append('<li><a data-toggle="tab" href="#' + this.id + '">' + $(this).children('.object-infos').data('object-label') + '</a></li>');
          field.find('> .controls .add_nested_fields').removeClass('add_nested_fields').html($(this).children('.object-infos').data('object-label'));
          nav.append('<li><a data-toggle="tab" href="#' + this.id + '">' + $(this).children('.object-infos').data('object-label') + '</a></li>');

Fixed code:
    new_tab = $('<li></li>').append(
        $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + field.attr('id')).text(field.children('.object-infos').data('object-label'))
    )
      controls.find('.add_nested_fields').removeClass('add_nested_fields').text(field.children('.object-infos').data('object-label'));
          nav.append(
              $('<li></li>').append(
                  $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + this.id).text($(this).children('.object-infos').data('object-label'))
              )
          );
          field.find('> .controls .add_nested_fields').removeClass('add_nested_fields').text($(this).children('.object-infos').data('object-label'));
          nav.append(
              $('<li></li>').append(
                  $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + this.id).text($(this).children('.object-infos').data('object-label'))
              )
          );

    context 'when XSS attack is attempted', js: true do
      it 'does not break on adding a new item' do
        allow(I18n).to receive(:t).and_call_original
        expect(I18n).to receive(:t).with('admin.form.new_model', name: 'Nested field test').and_return('<script>throw "XSS";</script>')
        @record = FactoryBot.create :field_test
        visit edit_path(model_name: 'field_test', id: @record.id)
        find('#field_test_nested_field_tests_attributes_field .add_nested_fields').click
      end

      it 'does not break on editing an existing item' do
        @record = FactoryBot.create :field_test
        NestedFieldTest.create! title: '<script>throw "XSS";</script>', field_test: @record
        visit edit_path(model_name: 'field_test', id: @record.id)
      end
    end

    context 'when XSS attack is attempted', js: true do
      it 'does not break on adding a new item' do
        allow(I18n).to receive(:t).and_call_original
        expect(I18n).to receive(:t).with('admin.form.new_model', name: 'Comment').and_return('<script>throw "XSS";</script>')
        @record = FactoryBot.create :field_test
        visit edit_path(model_name: 'field_test', id: @record.id)
        find('#field_test_comment_attributes_field .add_nested_fields').click
      end

      it 'does not break on adding an existing item' do
        RailsAdmin.config Comment do
          object_label_method :content
        end
        @record = FactoryBot.create :field_test
        FactoryBot.create :comment, content: '<script>throw "XSS";</script>', commentable: @record
        visit edit_path(model_name: 'field_test', id: @record.id)
      end
    end