GHSA-6hm7-3pwj-22rm Gitea: Denial of Service (CPU & Memory Exhaustion) via O(N^2) String Concatenation in Debian Package Upload
Gitea's Debian package registry parser contains an unbounded decompression vulnerability in [ParseControlFile](https://github.com/go-gitea/gitea/blob/689ace1ce28fd74244b8aa335d9928cdbf6b22f9/modules/packages/debian/metadata.go#L140). When processing an uploaded `.deb` file, the parser decompresses `control.tar.gz` and copies the entire uncompressed stream into a `strings.Builder` via a `TeeReader`, with no limit on how much data is read. Because `DEFLATE` compression can achieve ratios exceeding 100:1 on repetitive input, an attacker can craft an 83 MB `.deb` payload that expands to over 16 GB during parsing, exhausting server memory before any content validation runs. A second issue compounds this: continuation lines in the Description field are concatenated with `+=` at [modules/packages/debian/metadata.go:161](https://github.com/go-gitea/gitea/blob/689ace1ce28fd74244b8aa335d9928cdbf6b22f9/modules/packages/debian/metadata.go#L161) inside a loop, producing `O(N²)` allocation and copy work that stalls the CPU even at moderate line counts. Any authenticated user with write access to the package registry can trigger a complete denial of service with a single upload request to the handler at [routers/api/packages/debian/debian.go:146](https://github.com/go-gitea/gitea/blob/689ace1ce28fd74244b8aa335d9928cdbf6b22f9/routers/api/packages/debian/debian.go#L146).Root CauseThere are two distinct root causes that can be exploited independently or together.**1. Unbounded decompression (decompression bomb)**
ParsePackage wraps the control.tar member in a decompressor but never constrains how many bytes that decompressor is allowed to produce:https://github.com/go-gitea/gitea/blob/9155a81b9daf1d46b2380aa91271e623ac947c1e/modules/packages/debian/metadata.go#L88-L110The resulting inner reader is passed directly to the tar reader, and from there to `ParseControlFile`. Inside `ParseControlFile`,
every byte that the `bufio.Scanner` reads from the decompressed stream is simultaneously written into an unbounded
`strings.Builder` via `io.TeeReader`:https://github.com/go-gitea/gitea/blob/9155a81b9daf1d46b2380aa91271e623ac947c1e/modules/packages/debian/metadata.go#L147-L150There is no call to io.LimitReader at any point in this chain. Other package format parsers in the same codebase — pub, conan, and cargo — all wrap their readers with `io.LimitReader` before consuming them. The Debian parser does not, making it the only one in the registry vulnerable to this class of attack.**2. O(N²) string concatenation**
For each continuation line belonging to the Description field, the parser appends to a plain string with +=:https://github.com/go-gitea/gitea/blob/9155a81b9daf1d46b2380aa91271e623ac947c1e/modules/packages/debian/metadata.go#L158-L164Because Go strings are immutable, every `+=` allocates a new backing array and copies the entire accumulated description into it. A description with N continuation lines triggers O(N²) total bytes of allocation and copying. At 500 000 lines this produces roughly 250 GB of cumulative copy work, saturating a CPU core and driving the GC into a tight collection loop regardless of available RAM.ReproducingI have reproduced the issue in a Docker container with the following PoC. It may need tweaks based on the memory you are reproducing it with.This has been reproduced on commit `9155a81b9daf1d46b2380aa91271e623ac947c1e`.All the files go in the gitea file directory.`cmd/poc/main.go``Dockerfile.poc`Now run the PoC in the Docker container with:You will see the following when running the container (see the heap allocation growing towards the end):
CVSS v4.0 score: 7.1