Vendor: Ruby on Rails
Vendor URL: https://rubyonrails.org
Versions affected: versions prior to 7.0.2.4, 6.1.5.1, 6.0.4.8, 5.2.7.1
Operating Systems Affected: ALL
Author: Álvaro Martín Fraguas 
Advisory URLs:
- https://groups.google.com/g/rubyonrails-security/c/Yg2tEh2UUqc
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-27777
Accepted commit for the fix in the official master branch:
- https://github.com/rails/rails/commit/649516ce0feb699ae06a8c5e81df75d460cc9a85
Risk: Medium (XSS vulnerability in some cases for some Rails methods).

Summary

Ruby on Rails is a web application framework that follows the Model-view-controller (MVC) pattern. It offers some protections against Cross-site scripting (XSS) attacks in its helpers for the views. Several tag helpers in ActionView::Helpers::FormTagHelper and ActionView::Helpers::TagHelper are vulnerable against XSS because their current protection does not restrict properly the set of characters allowed in the names of tag attributes and in the names of tags.

Impact

In some cases, Ruby on Rails applications that use the aforementioned helpers with user-supplied input are vulnerable to XSS attacks. Through them, it is possible to steal passwords or other private information from the user, substitute parts of the website with fake content, perform scans of the network of the user, etc.

Details

The first group of vulnerabilities is related to the options argument in methods from FormTagHelper like check_box_tag, label_tag, radio_button_tag, select_tag, submit_tag, text_area_tag, text_field_tag, etc. In particular in these 3 cases:

  • When providing prefixed HTML data-* attributes.
  • When providing prefixed HTML aria-* attributes.
  • When providing a hash of other types of non-boolean attributes.

For example:

check_box_tag('thename', 'thevalue', false, data: { malicious_input => 'thevalueofdata' })

In that method call, when the variable malicious_input is controlled in part or completely by a user of the application, an attacker can provide an input that will break free from the tag and execute arbitrary JavaScript code. For some applications, that code can be executed in the browser of a different user visiting the application. A simplified proof of concept with only reflected XSS would be this HTML ERB view file:

<%= check_box_tag('thename', 'thevalue', false, data: { params[:payload] => 'thevalueofdata' }) %>

Followed by a request that included the malicious URL parameter: http://...?payload=something="something">

That example only shows an alert window, but the vulnerability makes it possible to steal passwords or other private information from the user, substitute parts of the website with fake content, attack other websites visited by the user, perform scans of the network of the user, etc. And some applications are probably using more dangerous stored user input instead of URL parameters, allowing attackers to perform stored XSS attacks on other users.

Here is another example with aria-* HTML attributes were the same simple payload can be tested:

check_box_tag('thename', 'thevalue', false, aria: { malicious_input => 'thevalueofaria' })

And finally, another example with other non-boolean attributes:

check_box_tag('thename', 'thevalue', false, malicious_input => 'theothervalue')

This same vulnerable structure can also be attacked successfully in the other methods listed at the beginning of this post: label_tag, radio_button_tag, select_tag, submit_tag, text_area_tag, text_field_tag...

The second group of vulnerabilities is related to the more generic methods tag and content_tag from TagHelper. They are vulnerable in the options argument like the previous group of methods, but they are also vulnerable in their first argument, for the names of the generated tags, using the same kind of attack to break free from the tag and execute arbitrary Javascript code. For example:

  • tag(malicious_input)
  • tag.public_send(malicious_input.to_sym)
  • content_tag(malicious_input)

In the 3 cases, this is an example of a simple payload structure that works:

img%20src=%22/nonexistent%22%20onerror=%22javascript_payload%22

As said before for other examples, the vulnerability makes it possible to steal passwords or other private information from the user, substitute parts of the website with fake content, perform scans of the network of the user, etc.

Recommendation

If possible, update to any of the fixed versions: 7.0.2.4, 6.1.5.1, 6.0.4.8, 5.2.7.1

If updating is not an option, apply the patches provided in the official advisory: https://groups.google.com/g/rubyonrails-security/c/Yg2tEh2UUqc

Vendor Communication

2022-01-08 – Issue reported with patches through the official Ruby on Rails disclosure platform.
2022-04-26 – Release of patched Ruby on Rails versions, and official advisory published.
2022-05-06 – NCC Group advisory published.

Thanks to

Finding and fixing the vulnerabilities was the result of a personal research project that was part of the graduate training program at NCC Group. I would like to thank my colleagues at NCC Group for the opportunity to work there and the support they always provide. Especially:

  • Sergio de Miguel as my mentor, line manager and one of the leads of the graduate training program.
  • Daniel Romero as the regional research director in Spain.
  • David Muñoz as a lead of the graduate training program.

Also thanks to the Ruby on Rails core team and other contributors for making such an awesome web application framework, and to everyone who has helped me in my years as a Ruby on Rails developer.

About NCC Group

NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate & respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.