fix: 修复解压炸弹漏洞和goroutine泄漏

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
zerosaturation 2026-04-08 00:01:42 +08:00
parent f43b06e13d
commit 76a5eaaad9

View File

@ -62,6 +62,7 @@ type minimaxService struct {
jobs map[string]*ImageGenerationJob
jobsLock sync.RWMutex
client *http.Client
stopCh chan struct{}
}
// NewMinimaxService 创建 MiniMax 服务
@ -70,6 +71,7 @@ func NewMinimaxService(cfg *config.AssetConfig) MinimaxService {
config: cfg,
jobs: make(map[string]*ImageGenerationJob),
client: &http.Client{Timeout: 120 * time.Second},
stopCh: make(chan struct{}),
}
go svc.cleanupExpiredJobs()
return svc
@ -246,10 +248,21 @@ func (s *minimaxService) compressImageIfNeeded(imageURL string) (string, error)
return "", err
}
img, format, err := image.Decode(bytes.NewReader(imgData))
// First decode config to check dimensions (prevents decompression bomb)
cfg, format, err := image.DecodeConfig(bytes.NewReader(imgData))
if err != nil {
return "", err
}
// Limit decoded image to reasonable size (e.g., 4096x4096 = 64M pixels)
if int64(cfg.Width)*int64(cfg.Height) > 4096*4096 {
return "", fmt.Errorf("image too large: %dx%d", cfg.Width, cfg.Height)
}
// Full decode (already limited by size)
img, _, err := image.Decode(bytes.NewReader(imgData))
if err != nil {
return "", err
}
_ = format // suppress unused warning
bounds := img.Bounds()
maxDim := uint(1024)
@ -332,7 +345,12 @@ func validateURL(rawURL string) error {
// cleanupExpiredJobs 清理过期任务
func (s *minimaxService) cleanupExpiredJobs() {
ticker := time.NewTicker(1 * time.Hour)
for range ticker.C {
defer ticker.Stop()
for {
select {
case <-s.stopCh:
return
case <-ticker.C:
s.jobsLock.Lock()
now := time.Now().UnixMilli()
expiredThreshold := int64(24 * 60 * 60 * 1000) // 24h
@ -345,4 +363,10 @@ func (s *minimaxService) cleanupExpiredJobs() {
}
s.jobsLock.Unlock()
}
}
}
// Close 关闭服务
func (s *minimaxService) Close() {
close(s.stopCh)
}