sinatra/rack-protection

Path traversal middleware stops sinatra route from matching

Closed this issue · 2 comments

In our sinatra app, we have a route like this:

get "/links-to/:site_root" do
  # ...
end

Where :site_root can be a simple domain name (e.g. /links-to/foo.com) or a domain + path (e.g. /links-to/foo.com%2Fblog). The route matched both of these examples just fine until we upgraded to rack-protection 1.5.3 -- then we started getting 404s. It looks like we're getting 404s because of 7875ec5 (from #54) -- in it, it changed the unescaping from path.gsub('%2e', '.').gsub('%2f', '/'), which would not match against capitals to path.gsub(/%2e/i, '.').gsub(/%2f/i, '/') which does map against capitals. So I guess we've actually been lucky that the client (which we control) encodes / as %2F rather than %2f.

It appears this is all by design. Given how the path traversal middleware works, is there a way to make the sinatra match a request like /links-to/foo.com%2Fblog? I'm going to look into disabling the path traversal middleware (which will likely fix the problem), but it would be nice to not have to do that. It seems like a pretty big gotcha of the middleware that it affects what sinatra routes match.

rkh commented

Yes, this is by design, it is actually extremely close to the main use case as to why path traversal was introduced.

Quite a few Sinatra apps do the following:

get '/page/:name' do
  erb params[:name].to_sym
end

The assumption that it wouldn't match a slash is obviously wrong. If you don't use captures in file paths, you can disable the path traversal middleware:

set :protection, except: :path_traversal

Thanks, the set line works perfectly.