Skip to content

Commit

Permalink
Only write relative URIs when their normalized path begins with the n…
Browse files Browse the repository at this point in the history
…ormalized cache directory path

[CVE-2020-8159]
  • Loading branch information
JackMc authored and tenderlove committed May 6, 2020
1 parent b775ea2 commit 127da70
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
13 changes: 12 additions & 1 deletion lib/action_controller/caching/pages.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ def cache_directory
end
end

def normalized_cache_directory
File.expand_path(cache_directory)
end

def handle_proc_cache_directory
if @controller
@controller.instance_exec(&@cache_directory)
Expand Down Expand Up @@ -153,15 +157,22 @@ def cache_file(path, extension)
end

def cache_path(path, extension = nil)
File.join(cache_directory, cache_file(path, extension))
unnormalized_path = File.join(normalized_cache_directory, cache_file(path, extension))
normalized_path = File.expand_path(unnormalized_path)

relative_path if normalized_path.start_with?(normalized_cache_directory)
end

def delete(path)
return unless path

File.delete(path) if File.exist?(path)
File.delete(path + ".gz") if File.exist?(path + ".gz")
end

def write(content, path, gzip)
return unless path

FileUtils.makedirs(File.dirname(path))
File.open(path, "wb+") { |f| f.write(content) }

Expand Down
21 changes: 21 additions & 0 deletions test/caching_test.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
require "abstract_unit"
require "mocha/setup"
require "find"

CACHE_DIR = "test_cache"
# Don't change "../tmp" cavalierly or you might hose something you don't want hosed
TEST_TMP_DIR = File.expand_path("../tmp", __FILE__)
FILE_STORE_PATH = File.join(TEST_TMP_DIR, CACHE_DIR)


module PageCachingTestHelpers
def setup
super
Expand Down Expand Up @@ -175,6 +177,25 @@ class PageCachingTest < ActionController::TestCase
include PageCachingTestHelpers
tests PageCachingTestController

def test_cache_does_not_escape
draw do
get "/page_caching_test/ok/:id", to: "page_caching_test#ok"
end

project_root = File.expand_path("../../", __FILE__)


# Make a path that escapes the cache directory
get_to_root = "../../../"

# Make sure this relative path points at the project root
assert_equal project_root, File.expand_path(File.join(FILE_STORE_PATH, get_to_root))

get :ok, params: { id: "#{get_to_root}../pwnd" }

assert_predicate Find.find(File.join(project_root, "test")).grep(/pwnd/), :empty?
end

def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
draw do
get "posts.:format", to: "posts#index", as: :formatted_posts
Expand Down

1 comment on commit 127da70

@utkarsh2102
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @tenderlove, @JackMc,

Is it possible to get a patch for this to backport for v1.0.x?
Downstream maintainers need to patch this library for the LTS support! It'd be really helpful (& great) if a patch for this could be created! 😄

Please sign in to comment.