diff --git a/http/utils.go b/http/utils.go index a1611ce5..03615263 100644 --- a/http/utils.go +++ b/http/utils.go @@ -9,6 +9,7 @@ import ( "strings" libErrors "github.com/filebrowser/filebrowser/v2/errors" + imgErrors "github.com/filebrowser/filebrowser/v2/img" ) func renderJSON(w http.ResponseWriter, _ *http.Request, data interface{}) (int, error) { @@ -42,6 +43,8 @@ func errToStatus(err error) int { return http.StatusBadRequest case errors.Is(err, libErrors.ErrRootUserDeletion): return http.StatusForbidden + case errors.Is(err, imgErrors.ErrImageTooLarge): + return http.StatusRequestEntityTooLarge default: return http.StatusInternalServerError } diff --git a/img/service.go b/img/service.go index 2791c387..34a84c67 100644 --- a/img/service.go +++ b/img/service.go @@ -19,6 +19,15 @@ import ( // ErrUnsupportedFormat means the given image format is not supported. var ErrUnsupportedFormat = errors.New("unsupported image format") +// ErrImageTooLarge means the image is too large to create a thumbnail. +var ErrImageTooLarge = errors.New("image too large for thumbnail generation") + +// Maximum dimensions for thumbnail generation to prevent server crashes +const ( + MaxImageWidth = 10000 + MaxImageHeight = 10000 +) + // Service type Service struct { sem semaphore.Semaphore @@ -187,11 +196,17 @@ func (s *Service) detectFormat(in io.Reader) (Format, io.Reader, error) { buf := &bytes.Buffer{} r := io.TeeReader(in, buf) - _, imgFormat, err := image.DecodeConfig(r) + imgConfig, imgFormat, err := image.DecodeConfig(r) if err != nil { return 0, nil, fmt.Errorf("%s: %w", err.Error(), ErrUnsupportedFormat) } + // Check if image dimensions exceed maximum allowed size + if imgConfig.Width > MaxImageWidth || imgConfig.Height > MaxImageHeight { + return 0, nil, fmt.Errorf("image dimensions %dx%d exceed maximum %dx%d: %w", + imgConfig.Width, imgConfig.Height, MaxImageWidth, MaxImageHeight, ErrImageTooLarge) + } + format, err := ParseFormat(imgFormat) if err != nil { return 0, nil, ErrUnsupportedFormat