Skip to content

Commit

Permalink
Check for absolute paths in server URL before passing to find
Browse files Browse the repository at this point in the history
Various double slashes and URL encodings can bypass current checks.
In the case of the file existing, the server will 500 instead of 403
which leaks the existence but not the contents of the file.

Props to @eadz for finding this.
  • Loading branch information
josh committed Oct 28, 2014
1 parent abd1827 commit 3043d14
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 9 deletions.
14 changes: 7 additions & 7 deletions lib/sprockets/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ def call(env)
# Extract the path from everything after the leading slash
path = unescape(env['PATH_INFO'].to_s.sub(/^\//, ''))

# URLs containing a `".."` are rejected for security reasons.
if forbidden_request?(path)
return forbidden_response
end

# Strip fingerprint
if fingerprint = path_fingerprint(path)
path = path.sub("-#{fingerprint}", '')
end

# URLs containing a `".."` are rejected for security reasons.
if forbidden_request?(path)
return forbidden_response
end

# Look up the asset.
asset = find_asset(path, :bundle => !body_only?(env))

Expand Down Expand Up @@ -90,7 +90,7 @@ def forbidden_request?(path)
#
# http://example.org/assets/../../../etc/passwd
#
path.include?("..")
path.include?("..") || Pathname.new(path).absolute?
end

# Returns a 403 Forbidden response tuple
Expand Down Expand Up @@ -222,7 +222,7 @@ def headers(env, asset, length)
# # => "0aa2105d29558f3eb790d411d7d8fb66"
#
def path_fingerprint(path)
path[/-([0-9a-f]{7,40})\.[^.]+$/, 1]
path[/-([0-9a-f]{7,40})\.[^.]+\z/, 1]
end

# URI.unescape is deprecated on 1.9. We need to use URI::Parser
Expand Down
22 changes: 20 additions & 2 deletions test/test_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,28 @@ def app
end

test "illegal require outside load path" do
get "/assets/../config/passwd"
get "/assets//etc/passwd"
assert_equal 403, last_response.status

get "/assets/%2e%2e/config/passwd"
get "/assets/%2fetc/passwd"
assert_equal 403, last_response.status

get "/assets//%2fetc/passwd"
assert_equal 403, last_response.status

get "/assets/%2f/etc/passwd"
assert_equal 403, last_response.status

get "/assets/../etc/passwd"
assert_equal 403, last_response.status

get "/assets/%2e%2e/etc/passwd"
assert_equal 403, last_response.status

get "/assets/.-0000000./etc/passwd"
assert_equal 403, last_response.status

get "/assets/.-0000000./etc/passwd"
assert_equal 403, last_response.status
end

Expand Down

0 comments on commit 3043d14

Please sign in to comment.