From bd55c22768a20002ffb9761172f2a1f48d47f890 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 16 Jan 2026 08:12:30 -0300 Subject: [PATCH] khatru/blossom: ensure we don't get tricked by Content-Length. --- khatru/blossom/handlers.go | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/khatru/blossom/handlers.go b/khatru/blossom/handlers.go index 8da9aeb..e6fbf82 100644 --- a/khatru/blossom/handlers.go +++ b/khatru/blossom/handlers.go @@ -3,6 +3,7 @@ package blossom import ( "crypto/sha256" "encoding/json" + "fmt" "io" "mime" "net/http" @@ -67,13 +68,13 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) { // get the file size from the incoming header size, _ := strconv.Atoi(r.Header.Get("Content-Length")) - if size == 0 { + if size <= 0 { blossomError(w, "missing \"Content-Length\" header", 400) return } // read first bytes of upload so we can find out the filetype - b := make([]byte, min(50, size), size) + b := make([]byte, min(50, size), size+1 /* the extra 1 is for checking the validity of the Content-Length */) if n, err := r.Body.Read(b); err != nil && n != size { blossomError(w, "failed to read initial bytes of upload body: "+err.Error(), 400) return @@ -102,25 +103,28 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) { } // if it passes then we have to read the entire thing into memory so we can compute the sha256 - for { - var n int - n, err = r.Body.Read(b[len(b):cap(b)]) - b = b[:len(b)+n] - if err != nil { + // we will only read as much as specified in the Content-Length header + if size > len(b) { + alreadyRead := len(b) + for { + n, err := r.Body.Read(b[alreadyRead : size+1]) + alreadyRead += n if err == io.EOF { - err = nil + break + } else if err != nil && err != io.EOF { + blossomError(w, "failed to read upload body: "+err.Error(), 400) + return + } + if alreadyRead > size { + blossomError(w, "file is bigger than was specified in Content-Length", 400) + return } - break } - if len(b) == cap(b) { - // add more capacity (let append pick how much) - // if Content-Length was correct we shouldn't reach this - b = append(b, 0)[:len(b)] + if alreadyRead != size { + blossomError(w, fmt.Sprintf("got a %d bytes but Content-Length said %d", alreadyRead, size), 400) + return } - } - if err != nil { - blossomError(w, "failed to read upload body: "+err.Error(), 400) - return + b = b[0:size] } hash := sha256.Sum256(b)