mirror of
https://github.com/rclone/rclone.git
synced 2026-07-09 07:15:27 -04:00
serve restic: fix --private-repos isolation bypass CVE-2026-59733
A user could reach another user's private repository by sending a path
such as /<me>/../<victim>/config. The authorization check compares the
first path segment against the authenticated user, while the backend
object key was built from the raw, un-cleaned URL path.
Reject any non-canonical request path so the authorization segment and
the backend object key can no longer disagree.
Fixes GHSA-fqj9-69pf-6pjg
(cherry picked from commit dade21c161)
This commit is contained in:
@@ -244,6 +244,12 @@ func WithRemote(next http.Handler) http.Handler {
|
||||
urlpath = r.URL.Path
|
||||
}
|
||||
urlpath = strings.Trim(urlpath, "/")
|
||||
// Reject any non-canonical path, in particular one containing ".."
|
||||
// traversal elements.
|
||||
if urlpath != "" && path.Clean(urlpath) != urlpath {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
parts := matchData.FindStringSubmatch(urlpath)
|
||||
// if no data directory, layout is flat
|
||||
if parts != nil {
|
||||
|
||||
@@ -75,4 +75,16 @@ func TestResticPrivateRepositories(t *testing.T) {
|
||||
checkRequest(t, router.ServeHTTP, req, []wantFunc{wantCode(http.StatusForbidden)})
|
||||
}
|
||||
|
||||
// Reaching another user's repo via a ".." traversal in the path must be
|
||||
// rejected even though the {userID} segment matches the authenticated user
|
||||
// (GHSA-fqj9-69pf-6pjg).
|
||||
reqs = []*http.Request{
|
||||
newAuthenticatedRequest(t, "GET", "/test/../other_user/config", nil, opt.Auth.BasicUser, opt.Auth.BasicPass),
|
||||
newAuthenticatedRequest(t, "POST", "/test/../other_user/config", strings.NewReader("evil"), opt.Auth.BasicUser, opt.Auth.BasicPass),
|
||||
newAuthenticatedRequest(t, "DELETE", "/test/../other_user/config", nil, opt.Auth.BasicUser, opt.Auth.BasicPass),
|
||||
}
|
||||
for _, req := range reqs {
|
||||
checkRequest(t, router.ServeHTTP, req, []wantFunc{wantCode(http.StatusBadRequest)})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user