diff --git a/backend/app/cmd/import.go b/backend/app/cmd/import.go index 421d05e7..8e2eb2f3 100644 --- a/backend/app/cmd/import.go +++ b/backend/app/cmd/import.go @@ -42,7 +42,7 @@ func (ic *ImportCommand) Execute(_ []string) error { } req.SetBasicAuth("admin", ic.AdminPasswd) - resp, err := client.Do(req.WithContext(ctx)) // closes request's reader + resp, err := client.Do(req.WithContext(ctx)) //nolint:gosec // importURL built from operator CLI flags, not user input; closes request's reader if err != nil { return fmt.Errorf("request failed for %s: %w", importURL, err) } diff --git a/backend/app/cmd/remap.go b/backend/app/cmd/remap.go index b2ee55ec..360455cd 100644 --- a/backend/app/cmd/remap.go +++ b/backend/app/cmd/remap.go @@ -34,13 +34,13 @@ func (rc *RemapCommand) Execute(_ []string) error { ctx, cancel := context.WithTimeout(context.Background(), rc.Timeout) defer cancel() remapURL := fmt.Sprintf("%s/api/v1/admin/remap?site=%s", rc.RemarkURL, rc.Site) - req, err := http.NewRequest(http.MethodPost, remapURL, rulesReader) + req, err := http.NewRequest(http.MethodPost, remapURL, rulesReader) //nolint:gosec // RemarkURL is operator CLI flag, not user input if err != nil { return fmt.Errorf("can't make remap request for %s: %w", remapURL, err) } req.SetBasicAuth("admin", rc.AdminPasswd) - resp, err := client.Do(req.WithContext(ctx)) + resp, err := client.Do(req.WithContext(ctx)) //nolint:gosec // see above if err != nil { return fmt.Errorf("request failed for %s: %w", remapURL, err) } diff --git a/backend/app/rest/api/migrator.go b/backend/app/rest/api/migrator.go index 51f7875e..52421018 100644 --- a/backend/app/rest/api/migrator.go +++ b/backend/app/rest/api/migrator.go @@ -73,6 +73,7 @@ func (m *Migrator) importFormCtrl(w http.ResponseWriter, r *http.Request) { return } + r.Body = http.MaxBytesReader(w, r.Body, 256*1024*1024) // hard cap on upload to prevent memory exhaustion if err := r.ParseMultipartForm(20 * 1024 * 1024); err != nil { // 20M max memory, if bigger will make a file rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't parse multipart form", rest.ErrDecode) return diff --git a/backend/app/rest/api/rest_private.go b/backend/app/rest/api/rest_private.go index 24d887d7..5ccc7642 100644 --- a/backend/app/rest/api/rest_private.go +++ b/backend/app/rest/api/rest_private.go @@ -731,6 +731,7 @@ func (s *private) deleteMeCtrl(w http.ResponseWriter, r *http.Request) { func (s *private) savePictureCtrl(w http.ResponseWriter, r *http.Request) { user := rest.MustGetUserInfo(r) + r.Body = http.MaxBytesReader(w, r.Body, 32*1024*1024) // hard cap on upload to prevent memory exhaustion if err := r.ParseMultipartForm(5 * 1024 * 1024); err != nil { // 5M max memory, if bigger will make a file rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't parse multipart form", rest.ErrDecode) return diff --git a/backend/app/store/image/fs_store.go b/backend/app/store/image/fs_store.go index 80120171..8a3835e6 100644 --- a/backend/app/store/image/fs_store.go +++ b/backend/app/store/image/fs_store.go @@ -147,8 +147,8 @@ func (f *FileSystem) Cleanup(_ context.Context, ttl time.Duration) error { age := time.Since(info.ModTime()) if age > (ttl + 100*time.Millisecond) { // delay cleanup triggering to allow commit log.Printf("[INFO] remove staging image %s, age %v", fpath, age) - rmErr := os.Remove(fpath) - _ = os.Remove(path.Dir(fpath)) // try to remove directory + rmErr := os.Remove(fpath) //nolint:gosec // staging dir is server-only, no untrusted symlinks land here + _ = os.Remove(path.Dir(fpath)) //nolint:gosec // same staging dir return rmErr } return nil