XSS Vulnerability in the `sanitize` helper of Ruby on Rails
There is an XSS vulnerability in the sanitize helper in Ruby on Rails. This vulnerability has been assigned the CVE
identifier CVE-2013-1857.
Versions Affected: All.
Not affected: None.
Fixed Versions: 3.2.13, 3.1.12, 2.3.18
Impact
------
The sanitize helper in Ruby on Rails is designed to filter HTML and remove all tags and attributes which could be
malicious. The code which ensured that URLs only contain supported protocols contained several bugs which could allow
an attacker to embed a tag containing a URL which executes arbitrary javascript code.
All users running an affected release should either upgrade or use one of the work arounds immediately.
Releases
--------
The 3.2.13 and 3.1.12 releases are available at the normal locations.
Workarounds
-----------
If you are unable to upgrade, you can place the following code into a file in config/initializers and it will replace
the method with the correct implementation.
module HTML
class WhiteListSanitizer
self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
def contains_bad_protocols?(attr_name, value)
uri_attributes.include?(attr_name) &&
(value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i &&
!allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
end
end
end
Patches
-------
To aid users who aren't able to upgrade immediately we have provided patches for the two supported release series.
They are in git-am format and consist of a single changeset.
* 3-2-sanitize_protocol.patch - Patch for 3.2 series
* 3-1-sanitize_protocol.patch - Patch for 3.1 series
* 3-0-sanitize_protocol.patch - Patch for 3.0 series
* 2-3-sanitize_protocol.patch - Patch for 2.3 series
Please note that only the 3.1.x and 3.2.x series are supported at present. Users of earlier unsupported releases are
advised to upgrade as soon as possible as we cannot guarantee the continued availability of security fixes for
unsupported releases.
Credits
-------
Thanks to Alan Jenkins <alan.christopher.jenkins () gmail com> for reporting the
vulnerability to us.
--
Aaron Patterson
http://tenderlovemaking.com/
2-3-sanitize_protocol.patch
Description:
From 10f0e6fe749d818c2d1296c04665a98345029b80 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson () gmail com>
Date: Fri, 15 Mar 2013 15:04:00 -0700
Subject: [PATCH] fix protocol checking in sanitization [CVE-2013-1857]
Conflicts:
actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
actionpack/test/controller/html-scanner/sanitizer_test.rb
---
.../vendor/html-scanner/html/sanitizer.rb | 8 ++++----
actionpack/test/controller/html-scanner/sanitizer_test.rb | 14 ++++++++++++++
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index a05ea0b..0fb82cb 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -62,8 +62,8 @@ module HTML
# A regular expression of the valid characters used to separate protocols like
# the ':' in 'http://foo.com'
- self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/
-
+ self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
+
# Specifies a Set of HTML attributes that can have URIs.
self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
@@ -166,8 +166,8 @@ module HTML
end
def contains_bad_protocols?(attr_name, value)
- uri_attributes.include?(attr_name) &&
- (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first))
+ uri_attributes.include?(attr_name) &&
+ (value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
end
end
end
diff --git a/actionpack/test/controller/html-scanner/sanitizer_test.rb b/actionpack/test/controller/html-scanner/sanitizer_test.rb
index 561ebc5..f72f66e 100644
--- a/actionpack/test/controller/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/controller/html-scanner/sanitizer_test.rb
@@ -169,6 +169,7 @@ class SanitizerTest < ActionController::TestCase
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="  javascript:alert('XSS');">),
+ %(<IMG SRC="javascript:alert('XSS');">),
%(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
assert_sanitized img_hack, "<img>"
@@ -270,6 +271,19 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized %{<a href=\"http://www.domain.com?var1=1&var2=2\">my link</a>}
end
+ def test_should_sanitize_neverending_attribute
+ assert_sanitized "<span class=\"\\", "<span class=\"\\\">"
+ end
+
+ def test_x03a
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ end
+
protected
def assert_sanitized(input, expected = nil)
@sanitizer ||= HTML::WhiteListSanitizer.new
--
1.8.1.1
3-0-sanitize_protocol.patch
Description:
From 77403a9b04073713e2b758c22174a81bb3cd62b9 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson () gmail com>
Date: Fri, 15 Mar 2013 15:04:00 -0700
Subject: [PATCH] fix protocol checking in sanitization [CVE-2013-1857]
Conflicts:
actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
---
.../action_controller/vendor/html-scanner/html/sanitizer.rb | 4 ++--
actionpack/test/template/html-scanner/sanitizer_test.rb | 10 ++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index 6cf4d27..b4c0b0f 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -65,7 +65,7 @@ module HTML
# A regular expression of the valid characters used to separate protocols like
# the ':' in 'http://foo.com'
- self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/
+ self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
# Specifies a Set of HTML attributes that can have URIs.
self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
@@ -170,7 +170,7 @@ module HTML
def contains_bad_protocols?(attr_name, value)
uri_attributes.include?(attr_name) &&
- (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first))
+ (value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
end
end
end
diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb
index d9853e8..aa0be26 100644
--- a/actionpack/test/template/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/template/html-scanner/sanitizer_test.rb
@@ -168,6 +168,7 @@ class SanitizerTest < ActionController::TestCase
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="  javascript:alert('XSS');">),
+ %(<IMG SRC="javascript:alert('XSS');">),
%(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
assert_sanitized img_hack, "<img>"
@@ -273,6 +274,15 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized "<span class=\"\\", "<span class=\"\\\">"
end
+ def test_x03a
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ end
+
protected
def assert_sanitized(input, expected = nil)
@sanitizer ||= HTML::WhiteListSanitizer.new
--
1.8.1.1
3-1-sanitize_protocol.patch
Description:
From 735bb985a202d0e0c38b6335159c17ec427b522b Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson () gmail com>
Date: Fri, 15 Mar 2013 15:04:00 -0700
Subject: [PATCH] fix protocol checking in sanitization [CVE-2013-1857]
Conflicts:
actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
---
.../action_controller/vendor/html-scanner/html/sanitizer.rb | 4 ++--
actionpack/test/template/html-scanner/sanitizer_test.rb | 10 ++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index 204e86f..57f05d8 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -66,7 +66,7 @@ module HTML
# A regular expression of the valid characters used to separate protocols like
# the ':' in 'http://foo.com'
- self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/
+ self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
# Specifies a Set of HTML attributes that can have URIs.
self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
@@ -171,7 +171,7 @@ module HTML
def contains_bad_protocols?(attr_name, value)
uri_attributes.include?(attr_name) &&
- (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first.downcase))
+ (value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
end
end
end
diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb
index ee3a52d..e9dc1e6 100644
--- a/actionpack/test/template/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/template/html-scanner/sanitizer_test.rb
@@ -176,6 +176,7 @@ class SanitizerTest < ActionController::TestCase
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="  javascript:alert('XSS');">),
+ %(<IMG SRC="javascript:alert('XSS');">),
%(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
assert_sanitized img_hack, "<img>"
@@ -281,6 +282,15 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized "<span class=\"\\", "<span class=\"\\\">"
end
+ def test_x03a
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ end
+
protected
def assert_sanitized(input, expected = nil)
@sanitizer ||= HTML::WhiteListSanitizer.new
--
1.8.1.1
3-2-sanitize_protocol.patch
Description:
From 99123ad12f71ce3e7fe70656810e53133665527c Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson () gmail com>
Date: Fri, 15 Mar 2013 15:04:00 -0700
Subject: [PATCH] fix protocol checking in sanitization [CVE-2013-1857]
Conflicts:
actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
---
.../action_controller/vendor/html-scanner/html/sanitizer.rb | 4 ++--
actionpack/test/template/html-scanner/sanitizer_test.rb | 10 ++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index 02eea58..994e115 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -66,7 +66,7 @@ module HTML
# A regular expression of the valid characters used to separate protocols like
# the ':' in 'http://foo.com'
- self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/
+ self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
# Specifies a Set of HTML attributes that can have URIs.
self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
@@ -171,7 +171,7 @@ module HTML
def contains_bad_protocols?(attr_name, value)
uri_attributes.include?(attr_name) &&
- (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first.downcase))
+ (value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
end
end
end
diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb
index 4e2ad4e..dee60c9 100644
--- a/actionpack/test/template/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/template/html-scanner/sanitizer_test.rb
@@ -176,6 +176,7 @@ class SanitizerTest < ActionController::TestCase
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="jav
ascript:alert('XSS');">),
%(<IMG SRC="  javascript:alert('XSS');">),
+ %(<IMG SRC="javascript:alert('XSS');">),
%(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
assert_sanitized img_hack, "<img>"
@@ -281,6 +282,15 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized "<span class=\"\\", "<span class=\"\\\">"
end
+ def test_x03a
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>"
+ assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">)
+ end
+
protected
def assert_sanitized(input, expected = nil)
@sanitizer ||= HTML::WhiteListSanitizer.new
--
1.8.1.1