Skip to content

Commit aed4d70

Browse files
committed
Add path checks in #send_file and #get_git_dir
The Grack::Server class should reject invalid paths supplied by the user using the regular expressions in line 10-23 of lib/grack/server.rb. This change adds some defense in depth against invalid paths.
1 parent e52740b commit aed4d70

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

Diff for: lib/grack/server.rb

+13-3
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@ def send_file(reqfile, content_type)
161161
reqfile = File.join(@dir, reqfile)
162162
return render_not_found if !F.exists?(reqfile)
163163

164+
if reqfile == File.realpath(reqfile)
165+
# reqfile looks legit: no path traversal, no leading '|'
166+
else
167+
# reqfile does not look trustworthy; abort
168+
return render_not_found
169+
end
170+
164171
@res = Rack::Response.new
165172
@res.status = 200
166173
@res["Content-Type"] = content_type
@@ -189,10 +196,13 @@ def send_file(reqfile, content_type)
189196
def get_git_dir(path)
190197
root = @config[:project_root] || Dir.pwd
191198
path = File.join(root, path)
192-
if File.exists?(path) # TODO: check is a valid git directory
193-
return path
199+
if !File.exists?(path)
200+
false
201+
elsif File.realpath(path) != path # looks like path traversal
202+
false
203+
else
204+
path # TODO: check is a valid git directory
194205
end
195-
false
196206
end
197207

198208
def get_service_type

Diff for: tests/main_test.rb

+16
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,22 @@ def test_git_config_upload_pack
183183
assert_equal 404, session.last_response.status
184184
end
185185

186+
def test_send_file
187+
app1 = app
188+
app1.instance_variable_set(:@dir, Dir.pwd)
189+
# Reject path traversal
190+
assert_equal 404, app1.send_file('tests/../tests', 'text/plain').first
191+
# Reject paths starting with '|', avoid File.read('|touch /tmp/pawned; ls /tmp')
192+
assert_equal 404, app1.send_file('|tests', 'text/plain').first
193+
end
194+
195+
def test_get_git_dir
196+
# Guard against non-existent directories
197+
assert_equal false, app.get_git_dir('foobar')
198+
# Guard against path traversal
199+
assert_equal false, app.get_git_dir('/../tests')
200+
end
201+
186202
private
187203

188204
def r

0 commit comments

Comments
 (0)