Cloudreve's built-in image processor decodes user-supplied images with Go's standard-library decoders (image/png, image/jpeg, image/gif) and guards only the compressed file size — never the decoded pixel dimensions. Go's decoders allocate a pixel buffer sized bytesPerPixel × width × height taken straight from the image header (e.g. a PNG's IHDR), with no upper bound on width/height. A tiny (tens-of-bytes) image that declares enormous dimensions therefore forces a multi-gigabyte-to-terabyte allocation (make([]uint8, …)), exhausting memory. The resulting out-of-memory condition is a fatal Go runtime error / kernel OOM-kill that recover() cannot catch, terminating the whole Cloudreve process for all users.
Two reachable sinks share the same root cause:
PUT /api/v4/user/setting/avatar) — decodes synchronously in the request handler. Any authenticated user. Cleanest single-request PoC.Post-auth, low privilege. A single 65-byte upload deterministically takes the instance offline.
The built-in generator is the default image thumbnailer:
// inventory/setting.go @ 26b6b10
"thumb_builtin_enabled": "1", // ON by default
"thumb_builtin_max_size": "78643200", // 75 MB — a *file size* cap
"thumb_vips_enabled": "0", // libvips (which has its own limits) OFF by default
...
"avatar_size": "4194304", // 4 MB — a *file size* cap
Builtin.Generate checks the on-disk/entity size, then hands the raw bytes to the stdlib decoders:
// pkg/thumb/builtin.go:144-152 @ 26b6b10
func (b Builtin) Generate(ctx context.Context, es...
4.0.0-20260613024411-3607f79bb44cExploitability
AV:NAC:LPR:LUI:NScope
S:UImpact
C:NI:NA:H6.5/CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:HOther
Resource Management