fix: prevent symlink scope escape in copy/move/rename

Check WithinScope for src and dst in resourcePatchHandler before
fileutils.Copy/MoveFile, which follow symlinks and bypassed the
stat()/writeFile() guards (GHSA-239w-m3h6-ch8v).
This commit is contained in:
Henrique Dias 2026-06-03 12:21:23 +02:00
parent 103acd15fe
commit cdd666fc95
No known key found for this signature in database

View file

@ -228,6 +228,19 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
return http.StatusForbidden, nil
}
// Refuse to copy/move through a symlink that escapes the user's scope,
// for either the source (read escape) or the destination (write
// escape). fileutils.Copy/MoveFile operate on the raw afero FS and
// follow symlinks, so they bypass the guards in stat()/writeFile().
for _, p := range []string{src, dst} {
if ok, scopeErr := files.WithinScope(d.user.Fs, p); scopeErr != nil || !ok {
if scopeErr != nil {
return errToStatus(scopeErr), scopeErr
}
return http.StatusForbidden, nil
}
}
err = checkParent(src, dst)
if err != nil {
return http.StatusBadRequest, err