Affected Component
Core Services (Frontend UI/Backend API)
Describe the bug
What happened:
Directory and multi-path ZIP downloads build the entire archive in a bytes.Buffer and only then send it, so the whole compressed archive is held on the heap before any response byte is written. Combined with the 2 GB upload/pull limits, an authenticated user with default User-role resource/flow-file permissions can store (or pull) a large, incompressible directory and request it as a ZIP, forcing the API process to allocate memory proportional to the archive size. A handful of concurrent requests can exhaust process/host memory and crash or severely degrade the API.
Single-file downloads are fine since they stream from disk. Only the directory / multi-path ZIP paths are affected.
WHat should happen:
We should probably create the zip writer over the response writer (zw := zip.NewWriter(c.Writer)) after setting Content-Type: application/zip and Content-Disposition, write entries, then zw.Close().
Steps to Reproduce
- As a
User-role account, upload (or pull from a flow container) a directory of incompressible data.
- Request the directory (or a multi-path selection) from the ZIP download endpoint.
- The handler calls
ZipResources / ZipDirectory / ZipRelativePaths with a bytes.Buffer; resident heap grows to roughly the archive size before the response starts.
- Issue a few concurrent requests → Go runtime fatal out-of-memory.
A standalone harness that calls the real ZipResources with a bytes.Buffer sink shows heap growth proportional to archive size (≈32 MiB incompressible input → ≈33.5 MiB ZIP → ≈105 MiB max heap) and crashes with a runtime OOM under a constrained ulimit -v, with the stack going through bytes.growSlice → bytes.(*Buffer).Write → archive/zip → io.Copy → resources.ZipResources.
System Configuration
Logs and Artifacts
No response
Screenshots or Recordings
No response
Verification
Affected Component
Core Services (Frontend UI/Backend API)
Describe the bug
What happened:
Directory and multi-path ZIP downloads build the entire archive in a
bytes.Bufferand only then send it, so the whole compressed archive is held on the heap before any response byte is written. Combined with the 2 GB upload/pull limits, an authenticated user with defaultUser-role resource/flow-file permissions can store (or pull) a large, incompressible directory and request it as a ZIP, forcing the API process to allocate memory proportional to the archive size. A handful of concurrent requests can exhaust process/host memory and crash or severely degrade the API.Single-file downloads are fine since they stream from disk. Only the directory / multi-path ZIP paths are affected.
WHat should happen:
We should probably create the zip writer over the response writer (
zw := zip.NewWriter(c.Writer)) after settingContent-Type: application/zipandContent-Disposition, write entries, thenzw.Close().Steps to Reproduce
User-role account, upload (or pull from a flow container) a directory of incompressible data.ZipResources/ZipDirectory/ZipRelativePathswith abytes.Buffer; resident heap grows to roughly the archive size before the response starts.A standalone harness that calls the real
ZipResourceswith abytes.Buffersink shows heap growth proportional to archive size (≈32 MiB incompressible input → ≈33.5 MiB ZIP → ≈105 MiB max heap) and crashes with a runtime OOM under a constrainedulimit -v, with the stack going throughbytes.growSlice→bytes.(*Buffer).Write→archive/zip→io.Copy→resources.ZipResources.System Configuration
Logs and Artifacts
No response
Screenshots or Recordings
No response
Verification