fix(security): bound cover download memory usage

This commit is contained in:
zarzet
2026-08-29 18:56:56 +07:00
parent 740ce173b2
commit 7556d93e80
2 changed files with 26 additions and 1 deletions
+8 -1
View File
@@ -36,6 +36,7 @@ func downloadCoverToMemory(coverURL string) ([]byte, error) {
const (
embeddedCoverJPEGQuality = 88
maxCoverDownloadBytes = 24 * 1024 * 1024
// Decoding arbitrary provider artwork allocates roughly four bytes per
// pixel. Refuse pathological images before Decode so a malicious extension
// cannot force an unbounded mobile allocation. Normal artwork through
@@ -298,11 +299,17 @@ func fetchCoverBytes(downloadURL string) ([]byte, error) {
if resp.StatusCode != 200 {
return nil, fmt.Errorf("cover download failed: HTTP %d", resp.StatusCode)
}
if resp.ContentLength > maxCoverDownloadBytes {
return nil, fmt.Errorf("cover download exceeds %d MiB limit", maxCoverDownloadBytes/(1024*1024))
}
data, err := io.ReadAll(resp.Body)
data, err := io.ReadAll(io.LimitReader(resp.Body, maxCoverDownloadBytes+1))
if err != nil {
return nil, fmt.Errorf("failed to read cover data: %w", err)
}
if len(data) > maxCoverDownloadBytes {
return nil, fmt.Errorf("cover download exceeds %d MiB limit", maxCoverDownloadBytes/(1024*1024))
}
width, height := coverDimensions(data)
GoLog("[Cover] Downloaded %d KB (%dx%d)", len(data)/1024, width, height)
+18
View File
@@ -2,10 +2,14 @@ package gobackend
import (
"bytes"
"fmt"
"image"
"image/color"
"image/jpeg"
"image/png"
"net/http"
"net/http/httptest"
"strings"
"sync"
"sync/atomic"
"testing"
@@ -151,6 +155,20 @@ func TestDownloadCoverUsesProviderURLUnchanged(t *testing.T) {
}
}
func TestFetchCoverBytesRejectsOversizedResponse(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
writer.Header().Set("Content-Length", fmt.Sprintf("%d", maxCoverDownloadBytes+1))
writer.WriteHeader(http.StatusOK)
}))
defer server.Close()
SetAllowPrivateNetwork(true)
defer SetAllowPrivateNetwork(false)
if _, err := fetchCoverBytes(server.URL); err == nil || !strings.Contains(err.Error(), "exceeds") {
t.Fatalf("expected oversized cover rejection, got %v", err)
}
}
func TestResizeCoverForEmbeddingPreservesAspectRatio(t *testing.T) {
original := encodedTestCover(t, 1200, 600, "jpeg")