VYPR
Moderate severityNVD Advisory· Published Jan 12, 2021· Updated Aug 4, 2024

CVE-2020-36190

CVE-2020-36190

Description

RailsAdmin (aka rails_admin) before 1.4.3 and 2.x before 2.0.2 allows XSS via nested forms.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

RailsAdmin before 1.4.3 and 2.x before 2.0.2 contains a cross-site scripting (XSS) vulnerability in nested forms via unsanitized object labels.

Vulnerability

Overview

CVE-2020-36190 is a cross-site scripting (XSS) vulnerability in RailsAdmin, a popular administration interface for Ruby on Rails applications. The flaw exists in the handling of nested forms, where user-controlled object labels are inserted into the DOM without proper sanitization. Specifically, the code used .html() to set the label text, allowing an attacker to inject arbitrary HTML and JavaScript [2]. This affects all versions before 1.4.3 and 2.x before 2.0.2 [1][3].

Exploitation

An attacker can exploit this vulnerability by crafting a malicious object label that contains JavaScript code. When a user interacts with a nested form (e.g., adding or viewing nested records), the injected script executes in the context of the victim's browser. The attack requires the ability to create or edit records that use nested forms, which typically implies administrative or privileged access to the RailsAdmin interface [4]. No authentication bypass is needed; the attacker must have legitimate access to the admin panel.

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the browser of any user viewing the affected nested form. This can lead to session hijacking, defacement, data theft, or further attacks against the admin interface. The vulnerability is classified as medium severity (CVSS 6.1) due to the requirement for authenticated access and user interaction [3].

Mitigation

The vulnerability was fixed in RailsAdmin versions 1.4.3 and 2.0.2. The fix replaces .html() with .text() when setting the object label, ensuring that user input is treated as text rather than HTML [2]. Users are strongly advised to upgrade to the latest patched version. No workarounds are documented; upgrading is the recommended course of action [1][4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
rails_adminRubyGems
< 1.4.31.4.3
rails_adminRubyGems
>= 2.0.0, < 2.0.22.0.2

Affected products

2

Patches

4
7a268dad1b1c

Version 2.0.2

https://github.com/sferik/rails_adminM.ShibuyaMar 17, 2020via osv
3 files changed · +19 2
  • CHANGELOG.md+12 1 modified
    @@ -2,7 +2,18 @@
     
     ## [Unreleased](https://github.com/sferik/rails_admin/tree/HEAD)
     
    -[Full Changelog](https://github.com/sferik/rails_admin/compare/v2.0.1...HEAD)
    +[Full Changelog](https://github.com/sferik/rails_admin/compare/v2.0.2...HEAD)
    +
    +
    +## [2.0.2](https://github.com/sferik/rails_admin/tree/v2.0.2) - 2020-03-17
    +
    +[Full Changelog](https://github.com/sferik/rails_admin/compare/v2.0.1...v2.0.2)
    +
    +### Fixed
    +- Fix to use I18n to translate the button 'Reset filters'([#3248](https://github.com/sferik/rails_admin/pull/3248))
    +
    +### Security
    +- Fix XSS vulnerability in nested forms([d72090ec](https://github.com/sferik/rails_admin/commit/d72090ec6a07c3b9b7b48ab50f3d405f91ff4375))
     
     
     ## [2.0.1](https://github.com/sferik/rails_admin/tree/v2.0.1) - 2019-12-31
    
  • lib/rails_admin/version.rb+1 1 modified
    @@ -2,7 +2,7 @@ module RailsAdmin
       class Version
         MAJOR = 2
         MINOR = 0
    -    PATCH = 1
    +    PATCH = 2
         PRE = nil
     
         class << self
    
  • README.md+6 0 modified
    @@ -16,6 +16,12 @@
     
     RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.
     
    +## Announcements
    +
    +### [Action required] Security issue
    +
    +**RailsAdmin 2.0.1, 2.0.0 and up to 1.4.2 have been reported to have XSS vulnerability.** We strongly recommend that you upgrade RailsAdmin to 2.0.2 (and higher) or 1.4.3 as soon as possible, if you are on those versions. See [d72090ec](https://github.com/sferik/rails_admin/commit/d72090ec6a07c3b9b7b48ab50f3d405f91ff4375) for the detail.
    +
     ## Getting started
     
     * Check out [the docs][docs].
    
3b505fc8d81e

Version 1.4.3

https://github.com/sferik/rails_adminM.ShibuyaMar 17, 2020via osv
2 files changed · +20 3
  • CHANGELOG.md+19 2 modified
    @@ -1,8 +1,25 @@
     # RailsAdmin Changelog
     
    -## [Unreleased](https://github.com/sferik/rails_admin/tree/HEAD)
    +## [Unreleased](https://github.com/sferik/rails_admin/tree/1.x-stable)
     
    -[Full Changelog](https://github.com/sferik/rails_admin/compare/v1.4.2...HEAD)
    +[Full Changelog](https://github.com/sferik/rails_admin/compare/v1.4.3...1.x-stable)
    +
    +
    +## [1.4.3](https://github.com/sferik/rails_admin/tree/v1.4.3) - 2020-03-17
    +
    +[Full Changelog](https://github.com/sferik/rails_admin/compare/v1.4.2...v1.4.3)
    +
    +### Fixed
    +- Fix NoMethodError when used with Rails 6.0 ([#3122](https://github.com/sferik/rails_admin/pull/3122))
    +- Fix wrong styles when using multiple instances of CodeMirror([#3107](https://github.com/sferik/rails_admin/pull/3107))
    +- Fix password being cleared when used with Devise 4.6([72bc0373](https://github.com/sferik/rails_admin/commit/72bc03736162ffef8e5b99f42ca605d17fe7e7d0))
    +- ActiveStorage factory caused const missing for Mongoid([#3088](https://github.com/sferik/rails_admin/pull/3088), [db927687](https://github.com/sferik/rails_admin/commit/db9276879c8e8c5e8772261725ef0e0cdadd9cf1))
    +- Fix exact matches were using LIKE, which was not index-friendly([#3000](https://github.com/sferik/rails_admin/pull/3000))
    +- Middleware check failed when using RedisStore([#3076](https://github.com/sferik/rails_admin/issues/3076))
    +- Fix field being reset to default after an error([#3066](https://github.com/sferik/rails_admin/pull/3066))
    +
    +### Security
    +- Fix XSS vulnerability in nested forms([872a637b](https://github.com/sferik/rails_admin/commit/872a637b118e0607eccd8b0b3b94e5f6f9db6758))
     
     
     ## [1.4.2](https://github.com/sferik/rails_admin/tree/v1.4.2) - 2018-09-23
    
  • lib/rails_admin/version.rb+1 1 modified
    @@ -2,7 +2,7 @@ module RailsAdmin
       class Version
         MAJOR = 1
         MINOR = 4
    -    PATCH = 2
    +    PATCH = 3
         PRE = nil
     
         class << self
    
d72090ec6a07

Fix XSS vulnerability in nested forms

4 files changed · +50 5
  • app/assets/javascripts/rails_admin/ra.nested-form-hooks.js+4 2 modified
    @@ -11,7 +11,9 @@
       $(document).on('nested:fieldAdded', 'form', function(content) {
         var controls, field, nav, new_tab, one_to_one, parent_group, toggler;
         field = content.field.addClass('tab-pane').attr('id', 'unique-id-' + (new Date().getTime()));
    -    new_tab = $('<li><a data-toggle="tab" href="#' + field.attr('id') + '">' + field.children('.object-infos').data('object-label') + '</a></li>');
    +    new_tab = $('<li></li>').append(
    +        $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + field.attr('id')).text(field.children('.object-infos').data('object-label'))
    +    )
         parent_group = field.closest('.control-group');
         controls = parent_group.children('.controls');
         one_to_one = controls.data('nestedone') !== void 0;
    @@ -27,7 +29,7 @@
         content.select(':hidden').show('slow');
         toggler.addClass('active').removeClass('disabled').children('i').addClass('icon-chevron-down').removeClass('icon-chevron-right');
         if (one_to_one) {
    -      controls.find('.add_nested_fields').removeClass('add_nested_fields').html(field.children('.object-infos').data('object-label'));
    +      controls.find('.add_nested_fields').removeClass('add_nested_fields').text(field.children('.object-infos').data('object-label'));
         }
       });
     
    
  • app/assets/javascripts/rails_admin/ra.widgets.js+11 3 modified
    @@ -137,7 +137,11 @@
             toggler = field.find('> .controls > .btn-group > .toggler');
             tab_content.children('.fields:not(.tab-pane)').addClass('tab-pane').each(function() {
               $(this).attr('id', 'unique-id-' + (new Date().getTime()) + Math.floor(Math.random() * 100000));
    -          nav.append('<li><a data-toggle="tab" href="#' + this.id + '">' + $(this).children('.object-infos').data('object-label') + '</a></li>');
    +          nav.append(
    +              $('<li></li>').append(
    +                  $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + this.id).text($(this).children('.object-infos').data('object-label'))
    +              )
    +          );
             });
             if (nav.find("> li.active").length === 0) {
               nav.find("> li > a[data-toggle='tab']:first").tab('show');
    @@ -165,8 +169,12 @@
             tab_content = field.find("> .tab-content");
             toggler = field.find('> .controls > .btn-group > .toggler');
             tab_content.children(".fields:not(.tab-pane)").addClass('tab-pane active').each(function() {
    -          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>');
    +          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'))
    +              )
    +          );
             });
             first_tab = nav.find("> li > a[data-toggle='tab']:first");
             first_tab.tab('show');
    
  • spec/integration/fields/has_many_association_spec.rb+16 0 modified
    @@ -211,6 +211,22 @@
             expect(page.body).to include('field_test_nested_field_tests_attributes_new_nested_field_tests_deeply_nested_field_tests_attributes_new_deeply_nested_field_tests_title')
           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: '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
       end
     
       context 'with not nullable foreign key', active_record: true do
    
  • spec/integration/fields/has_one_association_spec.rb+19 0 renamed
    @@ -91,6 +91,25 @@
           @record.reload
           expect(@record.comment).to be_nil
         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
       end
     
       context 'with custom primary_key option' do
    
d72090ec6a07

Fix XSS vulnerability in nested forms

https://github.com/sferik/rails_adminM.ShibuyaMar 14, 2020via ghsa
4 files changed · +50 5
  • app/assets/javascripts/rails_admin/ra.nested-form-hooks.js+4 2 modified
    @@ -11,7 +11,9 @@
       $(document).on('nested:fieldAdded', 'form', function(content) {
         var controls, field, nav, new_tab, one_to_one, parent_group, toggler;
         field = content.field.addClass('tab-pane').attr('id', 'unique-id-' + (new Date().getTime()));
    -    new_tab = $('<li><a data-toggle="tab" href="#' + field.attr('id') + '">' + field.children('.object-infos').data('object-label') + '</a></li>');
    +    new_tab = $('<li></li>').append(
    +        $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + field.attr('id')).text(field.children('.object-infos').data('object-label'))
    +    )
         parent_group = field.closest('.control-group');
         controls = parent_group.children('.controls');
         one_to_one = controls.data('nestedone') !== void 0;
    @@ -27,7 +29,7 @@
         content.select(':hidden').show('slow');
         toggler.addClass('active').removeClass('disabled').children('i').addClass('icon-chevron-down').removeClass('icon-chevron-right');
         if (one_to_one) {
    -      controls.find('.add_nested_fields').removeClass('add_nested_fields').html(field.children('.object-infos').data('object-label'));
    +      controls.find('.add_nested_fields').removeClass('add_nested_fields').text(field.children('.object-infos').data('object-label'));
         }
       });
     
    
  • app/assets/javascripts/rails_admin/ra.widgets.js+11 3 modified
    @@ -137,7 +137,11 @@
             toggler = field.find('> .controls > .btn-group > .toggler');
             tab_content.children('.fields:not(.tab-pane)').addClass('tab-pane').each(function() {
               $(this).attr('id', 'unique-id-' + (new Date().getTime()) + Math.floor(Math.random() * 100000));
    -          nav.append('<li><a data-toggle="tab" href="#' + this.id + '">' + $(this).children('.object-infos').data('object-label') + '</a></li>');
    +          nav.append(
    +              $('<li></li>').append(
    +                  $('<a></a>').attr('data-toggle', 'tab').attr('href', '#' + this.id).text($(this).children('.object-infos').data('object-label'))
    +              )
    +          );
             });
             if (nav.find("> li.active").length === 0) {
               nav.find("> li > a[data-toggle='tab']:first").tab('show');
    @@ -165,8 +169,12 @@
             tab_content = field.find("> .tab-content");
             toggler = field.find('> .controls > .btn-group > .toggler');
             tab_content.children(".fields:not(.tab-pane)").addClass('tab-pane active').each(function() {
    -          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>');
    +          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'))
    +              )
    +          );
             });
             first_tab = nav.find("> li > a[data-toggle='tab']:first");
             first_tab.tab('show');
    
  • spec/integration/fields/has_many_association_spec.rb+16 0 modified
    @@ -211,6 +211,22 @@
             expect(page.body).to include('field_test_nested_field_tests_attributes_new_nested_field_tests_deeply_nested_field_tests_attributes_new_deeply_nested_field_tests_title')
           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: '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
       end
     
       context 'with not nullable foreign key', active_record: true do
    
  • spec/integration/fields/has_one_association_spec.rb+19 0 renamed
    @@ -91,6 +91,25 @@
           @record.reload
           expect(@record.comment).to be_nil
         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
       end
     
       context 'with custom primary_key option' do
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.