aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Neves <arthurnn@gmail.com>2016-02-02 12:34:11 -0500
committerRafael Mendonça França <rafaelmfranca@gmail.com>2016-02-29 15:39:12 -0300
commit769b4d3f6638f8871bb7ca7ad3d076a3dcc9e1a9 (patch)
treeedda5caad1c6f069d2445f9243cd79833243f329
parentaf9b9132f82d1f468836997c716a02f14e61c38c (diff)
downloadrails-769b4d3f6638f8871bb7ca7ad3d076a3dcc9e1a9.tar.gz
rails-769b4d3f6638f8871bb7ca7ad3d076a3dcc9e1a9.tar.bz2
rails-769b4d3f6638f8871bb7ca7ad3d076a3dcc9e1a9.zip
Don't allow render(params) in view/controller
`render(params)` is dangerous and could be a vector for attackers. Don't allow calls to render passing params on views or controllers. On a controller or view, we should not allow something like `render params[:id]` or `render params`. That could be problematic, because an attacker could pass input that could lead to a remote code execution attack. This patch is also compatible when using strong parameters. CVE-2016-2098
-rw-r--r--actionpack/lib/action_view/renderer/renderer.rb5
-rw-r--r--actionpack/test/controller/render_test.rb53
-rw-r--r--actionpack/test/template/render_test.rb27
3 files changed, 79 insertions, 6 deletions
diff --git a/actionpack/lib/action_view/renderer/renderer.rb b/actionpack/lib/action_view/renderer/renderer.rb
index bf1b5a7d22..0f359899d6 100644
--- a/actionpack/lib/action_view/renderer/renderer.rb
+++ b/actionpack/lib/action_view/renderer/renderer.rb
@@ -11,6 +11,11 @@ module ActionView
# Main render entry point shared by AV and AC.
def render(context, options)
+ if (options.is_a?(HashWithIndifferentAccess) && !options.respond_to?(:permitted?)) ||
+ (options.respond_to?(:permitted?) && !options.permitted?)
+ raise ArgumentError, "render parameters are not permitted"
+ end
+
if options.key?(:partial)
render_partial(context, options)
else
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index bc42c6614a..de80b78272 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -70,6 +70,10 @@ class TestController < ActionController::Base
render :file => file
end
+ def dynamic_inline_render
+ render :inline => "<%= render(params) %>"
+ end
+
def conditional_hello_with_public_header
if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true)
render :action => 'hello_world'
@@ -245,12 +249,6 @@ class TestController < ActionController::Base
render :inline => "<%= action_name %>"
end
- def test_dynamic_render_file_hash
- assert_raises ArgumentError do
- get :dynamic_render, { :id => { :file => '../\\../test/abstract_unit.rb' } }
- end
- end
-
def accessing_controller_name_in_template
render :inline => "<%= controller_name %>"
end
@@ -742,6 +740,15 @@ class MetalTestController < ActionController::Metal
end
end
+class MetalWithoutAVTestController < ActionController::Metal
+ include AbstractController::Rendering
+ include ActionController::Rendering
+
+ def dynamic_params_render
+ render params
+ end
+end
+
class RenderTest < ActionController::TestCase
tests TestController
@@ -783,6 +790,29 @@ class RenderTest < ActionController::TestCase
end
end
+ def test_dynamic_render_file_hash
+ assert_raises ArgumentError do
+ get :dynamic_render, { :id => { :file => '../\\../test/abstract_unit.rb' } }
+ end
+ end
+
+ def test_dynamic_inline
+ assert_raises ArgumentError do
+ get :dynamic_render, { :id => { :inline => '<%= RUBY_VERSION %>' } }
+ end
+ end
+
+ def test_dynamic_render_on_view
+ file = Tempfile.new('_name')
+ file.write "secrets!"
+ file.flush
+
+ e = assert_raises ActionView::Template::Error do
+ get :dynamic_inline_render, { :file => file.path }
+ end
+ assert_equal "render parameters are not permitted", e.message
+ end
+
# :ported:
def test_simple_show
get :hello_world
@@ -1657,3 +1687,14 @@ class MetalRenderTest < ActionController::TestCase
assert_equal "NilClass", @response.body
end
end
+
+class MetalRenderWithoutAVTest < ActionController::TestCase
+ tests MetalWithoutAVTestController
+
+ def test_dynamic_params_render
+ e = assert_raises ArgumentError do
+ get :dynamic_params_render, { inline: '<%= RUBY_VERSION %>' }
+ end
+ assert_equal "render parameters are not permitted", e.message
+ end
+end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index f207ad731f..2d0466585f 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -133,6 +133,33 @@ module RenderTestCases
end
end
+ def test_render_with_params
+ params = { :inline => '<%= RUBY_VERSION %>' }.with_indifferent_access
+ assert_raises ArgumentError do
+ @view.render(params)
+ end
+ end
+
+ def test_render_with_strong_parameters
+ # compatibility with Strong Parameters gem
+ params = Class.new(HashWithIndifferentAccess).new
+ params[:inline] = '<%= RUBY_VERSION %>'
+ e = assert_raises ArgumentError do
+ @view.render(params)
+ end
+ assert_equal "render parameters are not permitted", e.message
+ end
+
+ def test_render_with_permitted_strong_parameters
+ # compatibility with Strong Parameters gem
+ params = Class.new(HashWithIndifferentAccess).new
+ params[:inline] = "<%= 'hello' %>"
+ def params.permitted?
+ true
+ end
+ assert_equal 'hello', @view.render(params)
+ end
+
def test_render_partial
assert_equal "only partial", @view.render(:partial => "test/partial_only")
end