Skip to content

Commit

Permalink
Merge pull request #1065 from jkowens/fix-null-byte
Browse files Browse the repository at this point in the history
Return 400 if Rack::File or Rack::Directory path contains null byte
  • Loading branch information
tenderlove committed May 4, 2016
2 parents 790edb1 + 4a6e0bc commit 4faf2c4
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 2 deletions.
14 changes: 13 additions & 1 deletion lib/rack/directory.rb
Expand Up @@ -71,14 +71,26 @@ def get(env)
script_name = env[SCRIPT_NAME]
path_info = Utils.unescape_path(env[PATH_INFO])

if forbidden = check_forbidden(path_info)
if bad_request = check_bad_request(path_info)
bad_request
elsif forbidden = check_forbidden(path_info)
forbidden
else
path = ::File.join(@root, path_info)
list_path(env, path, path_info, script_name)
end
end

def check_bad_request(path_info)
return if Utils.valid_path?(path_info)

body = "Bad Request\n"
size = body.bytesize
return [400, {CONTENT_TYPE => "text/plain",
CONTENT_LENGTH => size.to_s,
"X-Cascade" => "pass"}, [body]]
end

def check_forbidden(path_info)
return unless path_info.include? ".."

Expand Down
3 changes: 2 additions & 1 deletion lib/rack/file.rb
Expand Up @@ -38,8 +38,9 @@ def get(env)
end

path_info = Utils.unescape_path request.path_info
clean_path_info = Utils.clean_path_info(path_info)
return fail(400, "Bad Request") unless Utils.valid_path?(path_info)

clean_path_info = Utils.clean_path_info(path_info)
path = ::File.join(@root, clean_path_info)

available = begin
Expand Down
7 changes: 7 additions & 0 deletions lib/rack/utils.rb
Expand Up @@ -609,5 +609,12 @@ def clean_path_info(path_info)
end
module_function :clean_path_info

NULL_BYTE = "\0".freeze

def valid_path?(path)
path.valid_encoding? && !path.include?(NULL_BYTE)
end
module_function :valid_path?

end
end
7 changes: 7 additions & 0 deletions test/spec_directory.rb
Expand Up @@ -63,6 +63,13 @@ def setup
assert_match(res, /passed!/)
end

it "serve uri with URL encoded null byte (%00) in filenames" do
res = Rack::MockRequest.new(Rack::Lint.new(app))
.get("/cgi/test%00")

res.must_be :bad_request?
end

it "not allow directory traversal" do
res = Rack::MockRequest.new(Rack::Lint.new(app)).
get("/cgi/../test")
Expand Down
5 changes: 5 additions & 0 deletions test/spec_file.rb
Expand Up @@ -68,6 +68,11 @@ def file(*args)
assert_match(res, /ruby/)
end

it "serve uri with URL encoded null byte (%00) in filenames" do
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test%00")
res.must_be :bad_request?
end

it "allow safe directory traversal" do
req = Rack::MockRequest.new(file(DOCROOT))

Expand Down

0 comments on commit 4faf2c4

Please sign in to comment.