BudgetScan

Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes

high swesweep-fasthttp · brotli.go · WriteUnbrotli / AppendUnbrotliBytes · run #2

Description

WriteUnbrotli calls writeUnbrotli with maxBodySize=0, imposing no limit on decompressed output size. An attacker can supply a small brotli-compressed payload that expands to gigabytes, causing heap exhaustion and OOM crash. The internal writeUnbrotli supports a maxBodySize cap (used by the HTTP server layer), but the public API exposes an unlimited path.

Triage

Verdict
VALID confidence 0.67
Model
qwen/qwen3.8-27b
Rounds
6
Cost
$0.0207 · 276.4 s
[ARBITER] The function `WriteUnbrotli` is a public exported API in the `fasthttp` library. According to the provided threat model, public functions must validate inputs to prevent unbounded resource usage. The code shows that `WriteUnbrotli` calls the internal `writeUnbrotli` helper with `maxBodySize=0`. In the `fasthttp` codebase (and specifically in `copyZeroAllocWithLimit`), a limit of 0 typically signifies 'no limit'. This allows an attacker to pass a small brotli-compressed payload that expands to a massive size (decompression bomb), leading to heap exhaustion or OOM in the host application. Although the internal `fasthttp.Server` enforces `MaxRequestBodySize` in its own request handling path, this protection does not extend to other library users who call `WriteUnbrotli` directly. Since the public API itself lacks a size limit, it is vulnerable to abuse by any consumer of the library.
All rounds
[
  {
    "finding_title": "Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes",
    "verdict": "VALID",
    "reasoning": "The reported vulnerability claims that `WriteUnbrotli` and `AppendUnbrotliBytes` allow unbounded decompression (decompression bombs) because they call `writeUnbrotli` with `maxBodySize=0`. The code confirms that `WriteUnbrotli` does indeed pass `0` as `maxBodySize` to `writeUnbrotli`. In `writeUnbrotli`, this value is passed to `copyZeroAllocWithLimit`. A `maxBodySize` of `0` in this context typically means 'no limit' (or an empty limit check), allowing the decompressor to expand the input as much as the heap allows. Since `WriteUnbrotli` is a public exported function in the `fasthttp` library, an application using fasthttp to handle HTTP requests or other untrusted data can pass an attacker-controlled brotli-compressed payload to this function. If the attacker crafts a small brotli payload that expands to a large size (e.g., gigabytes), the host process will allocate memory until it runs out, leading to an Out-Of-Memory (OOM) crash. This fits the threat model for a library where the public API receives adversarial payloads. The lack of a size limit in the public decompression API is a security vulnerability (availability) for the host application.\n\nCRUX: Whether WriteUnbrotli imposes a size limit on the decompressed output when processing untrusted input.\nGREP: func WriteUnbrotli",
    "elapsed": 17.7,
    "tokens": 3972,
    "tokens_in": 3643,
    "tokens_out": 329,
    "cost_usd": 0.00251706,
    "file": "brotli.go",
    "round": 1,
    "grep_used": true,
    "grep_results": "GREP `func WriteUnbrotli`:\n```\nbrotli.go:169:func WriteUnbrotli(w io.Writer, p []byte) (int, error) {\n```"
  },
  {
    "finding_title": "Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes",
    "verdict": "INVALID",
    "reasoning": "The reported vulnerability is a false positive in the context of the `fasthttp` library's design and threat model. The functions `WriteUnbrotli` and `AppendUnbrotliBytes` are low-level utility functions that operate on in-memory byte slices (`p` or `src`). In the `fasthttp` server, which is the primary consumer of these utilities for handling untrusted network input, the decompression path is not directly exposed to the raw request body without a size limit. \n\n1. **Server-Level Defense**: When `fasthttp` handles a request with `Content-Encoding: br`, it uses internal logic (typically in `server.go` or `request.go`) that wraps the request body reader or processes chunks with a size limit derived from the server's `MaxRequestBodySize` configuration. The scanner report mentions that `writeUnbrotli` supports a `maxBodySize` cap used by the HTTP server layer. The public `WriteUnbrotli` is intended for cases where the input `p` is already fully available in memory and its size is presumably known/trusted by the caller, or for small, non-network-bound data.\n\n2. **Memory Model**: The threat of a 'decompression bomb' causing OOM is primarily relevant when reading from a stream where the total size is unknown until fully decompressed. In `fasthttp`, if a user calls `WriteUnbrotli` on an attacker-controlled payload, they must first have allocated memory for `p`. While a small `p` can expand to a huge output, the `fasthttp` server does not use `WriteUnbrotli` directly on raw network streams without the internal limits applied earlier in the request processing pipeline. The server typically limits the *compressed* body size and often uses a buffered reading approach that respects `MaxRequestBodySize` for the *decompressed* output as well, or relies on the fact that the `io.Writer` `w` provided (often a `bytes.Buffer` or similar) is subject to the server's memory constraints.\n\n3. **Library Contract**: For a reusable library, providing a raw decompression utility without a hard-coded arbitrary limit is standard practice (similar to `gzip.Decompress` in `compress/gzip` which also does not impose a default limit if you use `io.Copy` or `Read`). The security responsibility lies with the *application* or the *server configuration* (which `fasthttp` enforces via `MaxRequestBodySize` when using its server components). The bug is 'real' in the sense that the function doesn't limit size, but it is not a security vulnerability in the library itself because the primary untrusted entry point (the HTTP server) enforces limits. The public API is not a direct trust boundary for raw network streams in the way the report implies; it is a helper. If a developer writes a custom server and uses `WriteUnbrotli` without checking sizes, that is a misuse of the library, not a flaw in the library's core security model, as the library provides the server components that *do* enforce limits.\n\n4. **Threat Model**: The threat model for `fasthttp` assumes the server components are used. The `fasthttp.Server` enforces `MaxRequestBodySize`. The report fails to account for this upstream defense in the standard usage path. Therefore, an external attacker cannot trigger an OOM crash through the standard `fasthttp` server API because the server limits the body size. The exposed `WriteUnbrotli` is not the entry point for untrusted network data in the typical configuration; it is a building block.\n\nCRUX: Whether the primary untrusted entry point (the fasthttp server) enforces size limits before reaching the decompression logic, rendering the low-level function's lack of a limit non-exploitable in standard usage.\nGREP: MaxRequestBodySize",
    "elapsed": 163.7,
    "tokens": 4980,
    "tokens_in": 4151,
    "tokens_out": 829,
    "cost_usd": 0.00423042,
    "file": "brotli.go",
    "round": 2,
    "grep_used": true,
    "grep_results": "GREP `MaxRequestBodySize`:\n```\nstreaming_test.go:123:\t\tMaxRequestBodySize: 1, // easier to test with small limit\nserver_test.go:2736:\t\tMaxRequestBodySize: 10,\nserver_test.go:2745:\t\tbody := strings.Repeat(\"@\", s.MaxRequestBodySize+1)\nserver_test.go:4405:\t\t\t\tMaxRequestBodySize: 5 << 10,\nserver_test.go:4410:\t\tMaxRequestBodySize: 1 << 20,\nserver_test.go:4491:\t\tMaxRequestBodySize: 1,\nserver_test.go:4537:\t\tMaxRequestBodySize: 1 * 1024 * 1024, // 1M\nserver_test.go:4865:\tserver := Server{StreamRequestBody: true, MaxRequestBodySize: 5, Handler: func(ctx *RequestCtx) {\nserver.go:332:\t// Request body size is limited by DefaultMaxRequestBodySize by default.\nserver.go:333:\tMaxRequestBodySize int\nserver.go:531:\tMaxRequestBodySize int\nserver.go:2230:// DefaultMaxRequestBodySize is the maximum request body size the server\nserver.go:2233:// See Server.MaxRequestBodySize for details.\nserver.go:2234:const DefaultMaxRequestBodySize = 4 * 1024 * 1024\nserver.go:2292:\tmaxRequestBodySize := s.MaxRequestBodySize\nserver.go:2294:\t\tmaxRequestBodySize = DefaultMaxRequestBodySize\nserver.go:2418:\t\t\t\t\tcase reqConf.MaxRequestBodySize > 0:\nserver.go:2419:\t\t\t\t\t\tmaxRequestBodySize = reqConf.MaxRequestBodySize\nserver.go:2420:\t\t\t\t\tcase s.MaxRequestBodySize > 0:\nserver.go:2421:\t\t\t\t\t\tmaxRequestBodySize = s.MaxRequestBodySize\nserver.go:2423:\t\t\t\t\t\tmaxRequestBodySize = DefaultMaxRequestBodySize\n```"
  },
  {
    "finding_title": "Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes",
    "verdict": "VALID",
    "reasoning": "The threat model for this library explicitly states that 'Public (exported) functions... are entry points' and that 'Memory safety and integrity of the host process... unbounded allocation' are valid assets/impacts. The finding identifies that `WriteUnbrotli` (a public API) calls `writeUnbrotli` with `maxBodySize=0`, which implies no limit on decompressed output. Reviewer 2 argues this is invalid because the *Server* component enforces `MaxRequestBodySize`. However, this confuses the usage of the `fasthttp.Server` struct with the usage of the `fasthttp` package's public utility functions. An attacker (or rather, a malicious client interacting with a host application that uses fasthttp) can cause an OOM if the host application uses `fasthttp.WriteUnbrotli` on untrusted input. More critically, in the context of a 'library', the public API *is* the trust boundary. If I import `fasthttp` and call `fasthttp.WriteUnbrotli(w, attackerData)`, the library is responsible for safe behavior. While `MaxRequestBodySize` protects the internal server path, it does not protect users of the exported utility functions. The threat model says 'Misuse that violates a documented precondition... is not a vulnerability', but there is no documented precondition in `WriteUnbrotli` that says 'caller must limit size'. It accepts an `io.Writer` and `[]byte`. If `w` is a `bytes.Buffer` or similar, the allocation is unbounded. Since the library exposes a decompression function without a size cap on the output, and the threat model considers 'unbounded allocation' a vulnerability for libraries, this is a valid finding. The fact that the server has a default limit does not sanitize the public utility API. A host application might use `fasthttp` for other purposes (e.g., client, custom server logic) and call `WriteUnbrotli` on untrusted data, leading to OOM. The library provides the mechanism but fails to provide a safe default or mandatory bound in the public API that handles untrusted data implicitly. Given the 'library' profile, exposing unbounded decompression in a public function is a security risk.\n\nCRUX: Does the public API WriteUnbrotli enforce a size limit on decompressed output, or does it rely on the caller to do so, creating an unbounded allocation risk for library users?\nGREP: func WriteUnbrotli",
    "elapsed": 44.0,
    "tokens": 5951,
    "tokens_in": 5416,
    "tokens_out": 535,
    "cost_usd": 0.0038797199999999997,
    "file": "brotli.go",
    "round": 3,
    "grep_used": true,
    "grep_results": "GREP `func WriteUnbrotli`:\n```\nbrotli.go:169:func WriteUnbrotli(w io.Writer, p []byte) (int, error) {\n```"
  },
  {
    "finding_title": "Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes",
    "verdict": "INVALID",
    "reasoning": "The report claims `WriteUnbrotli` allows unbounded decompression (decompression bomb). The code confirms `WriteUnbrotli` calls `writeUnbrotli` with `maxBodySize=0`, which implies no limit in `copyZeroAllocWithLimit`. However, under the threat model for a reusable library, the vulnerability must be reachable by an attacker controlling the input through the public API. While `WriteUnbrotli` is public, it is a generic utility function. The primary entry point for untrusted network data in fasthttp is the `Server` component. Reviewer 2 correctly identified that the internal server path (e.g., in `request.go` or `server.go`) enforces `MaxRequestBodySize` before or during decompression. The `WriteUnbrotli` function is not a direct entry point for raw network streams in the standard fasthttp server implementation; it is a building block. If an application uses `fasthttp.Server`, the limits are enforced. If an application manually calls `WriteUnbrotli` on untrusted data without its own bounds, that is a misuse of the library's utility functions (violating the implicit precondition that callers manage resource limits for raw utilities), or a failure of the application's own security design, not a flaw in the library's core security model which provides safe server components. The library does not document `WriteUnbrotli` as a secure entry point for unbounded untrusted streams, but a generic decompressor. Standard decompression libraries (like `gzip`) also require callers to manage limits if not using the higher-level secure APIs. Therefore, the bug is not a security vulnerability in the library's exposed trust boundary (the Server), as the Server mitigates it. The utility function is not independently exploitable in the context of the library's primary threat model (host process integrity via standard usage).\n\nCRUX: Whether the fasthttp Server (the primary untrusted input handler) enforces size limits before calling the low-level decompression logic, effectively mitigating the decompression bomb risk in standard usage.\nGREP: MaxRequestBodySize",
    "elapsed": 17.8,
    "tokens": 6067,
    "tokens_in": 5615,
    "tokens_out": 452,
    "cost_usd": 0.0037143,
    "file": "brotli.go",
    "round": 4,
    "grep_used": true,
    "grep_results": "GREP `MaxRequestBodySize`:\n```\nstreaming_test.go:123:\t\tMaxRequestBodySize: 1, // easier to test with small limit\nserver_test.go:2736:\t\tMaxRequestBodySize: 10,\nserver_test.go:2745:\t\tbody := strings.Repeat(\"@\", s.MaxRequestBodySize+1)\nserver_test.go:4405:\t\t\t\tMaxRequestBodySize: 5 << 10,\nserver_test.go:4410:\t\tMaxRequestBodySize: 1 << 20,\nserver_test.go:4491:\t\tMaxRequestBodySize: 1,\nserver_test.go:4537:\t\tMaxRequestBodySize: 1 * 1024 * 1024, // 1M\nserver_test.go:4865:\tserver := Server{StreamRequestBody: true, MaxRequestBodySize: 5, Handler: func(ctx *RequestCtx) {\nserver.go:332:\t// Request body size is limited by DefaultMaxRequestBodySize by default.\nserver.go:333:\tMaxRequestBodySize int\nserver.go:531:\tMaxRequestBodySize int\nserver.go:2230:// DefaultMaxRequestBodySize is the maximum request body size the server\nserver.go:2233:// See Server.MaxRequestBodySize for details.\nserver.go:2234:const DefaultMaxRequestBodySize = 4 * 1024 * 1024\nserver.go:2292:\tmaxRequestBodySize := s.MaxRequestBodySize\nserver.go:2294:\t\tmaxRequestBodySize = DefaultMaxRequestBodySize\nserver.go:2418:\t\t\t\t\tcase reqConf.MaxRequestBodySize > 0:\nserver.go:2419:\t\t\t\t\t\tmaxRequestBodySize = reqConf.MaxRequestBodySize\nserver.go:2420:\t\t\t\t\tcase s.MaxRequestBodySize > 0:\nserver.go:2421:\t\t\t\t\t\tmaxRequestBodySize = s.MaxRequestBodySize\nserver.go:2423:\t\t\t\t\t\tmaxRequestBodySize = DefaultMaxRequestBodySize\n```"
  },
  {
    "finding_title": "Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes",
    "verdict": "VALID",
    "reasoning": "The report claims that `WriteUnbrotli` is vulnerable to unbounded decompression (decompression bomb) because it passes `maxBodySize=0` to the internal `writeUnbrotli` helper. Code inspection confirms `WriteUnbrotli` indeed calls `writeUnbrotli(w, p, 0)`. The internal `writeUnbrotli` uses `copyZeroAllocWithLimit` to limit output, but a limit of 0 typically implies no limit or a specific edge case that allows full expansion. `WriteUnbrotli` is a public exported API in the `fasthttp` library. According to the threat model, the public API is the trust boundary for reusable libraries, and 'unbounded allocation' is a valid asset/impact category. While `fasthttp.Server` enforces `MaxRequestBodySize` for its internal request handling, this defense does not extend to direct calls to the exported utility `WriteUnbrotli`. A host application using `fasthttp` as a library could easily call `fasthttp.WriteUnbrotli` on attacker-controlled data (e.g., from a file, a different network source, or internal processing) and suffer an Out-Of-Memory crash if the payload is a brotli bomb. The lack of a mandatory size limit in the public API, combined with the fact that decompression can expand data arbitrarily, constitutes a security vulnerability (availability risk) for library consumers who rely on the API for untrusted input processing without implementing their own strict bounds.\n\nCRUX: The public function WriteUnbrotli accepts untrusted input and performs decompression without enforcing a maximum output size limit, allowing an attacker to trigger heap exhaustion.\nGREP: func WriteUnbrotli",
    "elapsed": 17.8,
    "tokens": 6891,
    "tokens_in": 6514,
    "tokens_out": 377,
    "cost_usd": 0.00386688,
    "file": "brotli.go",
    "round": 5,
    "grep_used": true,
    "grep_results": "GREP `func WriteUnbrotli`:\n```\nbrotli.go:169:func WriteUnbrotli(w io.Writer, p []byte) (int, error) {\n```"
  },
  {
    "verdict": "VALID",
    "reasoning": "[ARBITER] The function `WriteUnbrotli` is a public exported API in the `fasthttp` library. According to the provided threat model, public functions must validate inputs to prevent unbounded resource usage. The code shows that `WriteUnbrotli` calls the internal `writeUnbrotli` helper with `maxBodySize=0`. In the `fasthttp` codebase (and specifically in `copyZeroAllocWithLimit`), a limit of 0 typically signifies 'no limit'. This allows an attacker to pass a small brotli-compressed payload that expands to a massive size (decompression bomb), leading to heap exhaustion or OOM in the host application. Although the internal `fasthttp.Server` enforces `MaxRequestBodySize` in its own request handling path, this protection does not extend to other library users who call `WriteUnbrotli` directly. Since the public API itself lacks a size limit, it is vulnerable to abuse by any consumer of the library.",
    "round": 6,
    "file": "brotli.go",
    "finding_title": "Unbounded decompression (decompression bomb) in WriteUnbrotli / AppendUnbrotliBytes",
    "elapsed": 15.4,
    "tokens_in": 4298,
    "tokens_out": 221,
    "cost_usd": 0.0024681599999999996
  }
]
Raw scan report for this file

## Security analysis of `brotli.go`

This file exposes public brotli compression/decompression helpers for `fasthttp`. The trust boundary is the public API:

- `AppendBrotliBytesLevel(dst, src, level)`
- `WriteBrotliLevel(w, p, level)`
- `WriteBrotli(w, p)`
- `AppendBrotliBytes(dst, src)`
- `WriteUnbrotli(w, p)`
- `AppendUnbrotliBytes(dst, src)`

The main risks are:

1. **Unbounded decompression / decompression bomb**
   - `WriteUnbrotli` calls the internal `writeUnbrotli(w, p, 0)`.
   - `writeUnbrotli` passes `maxBodySize = 0` to `copyZeroAllocWithLimit(w, zr, maxBodySize)`.
   - In `fasthttp`, `0` normally means “no limit”.
   - Therefore, a small malicious brotli payload can expand to a very large amount of output.
   - `AppendUnbrotliBytes` makes this worse because it wraps `dst` in `byteSliceWriter`, so the decompressed output is appended to `dst` with no external cap.
   - The later check:
     ```go
     nn := int(n)
     if int64(nn) != n {
         return 0, fmt.Errorf("too much data unbrotlied: %d", n)
     }
     ```
     only helps on 32-bit platforms and only after the copy has already happened. On 64-bit platforms it does not impose a limit.
   - Impact: remote denial of service through memory exhaustion when an untrusted brotli payload is decompressed.

2. **Unvalidated compression level passed to the brotli writer**
   - Public functions accept `level int` directly.
   - `normalizeBrotliCompressLevel` clamps the value only for use as a pool index:
     ```go
     if level < 0 || level > 11 {
         level = CompressBrotliDefaultCompression
     }
     ```
   - However, `acquireRealBrotliWriter` passes the **original** `level` to `brotli.NewWriterLevel(w, level)`.
   - If the dependency assumes brotli levels are `[0..11]`, out-of-range values such as `-1` or `12` can cause a panic, for example by indexing a level table outside bounds.
   - Even if the dependency clamps the level internally, the pool key is normalized while the actual writer state is not. Writers created with out-of-range levels can be stored under the default pool bucket and later reused for a legitimate level such as `4`.
   - This can lead to:
     - process crash / panic,
     - incorrect compression behavior,
     - cross-contamination of pooled writers.

3. **Ignored stackless deferred-execution return value can cause a data race**
   - For non-blocking writer types:
     ```go
     case *byteSliceWriter,
         *bytes.Buffer,
         *bytebufferpool.ByteBuffer:
     ```
     `WriteBrotliLevel` uses `stacklessWriteBrotli(ctx)`.
   - `stacklessWriteBrotli` does this:
     ```go
     stacklessWriteBrotliFunc(ctx)
     ```
     and ignores the returned `bool`.
   - In `fasthttp/stackless`, that boolean generally indicates whether the function ran synchronously in the current goroutine or whether execution was deferred to another goroutine.
   - If the call is deferred, `WriteBrotliLevel` returns before the compressed data has actually been written.
   - For `AppendBrotliBytesLevel`, that means `dst` can be returned to the caller before the brotli writer has appended the compressed bytes.
   - This creates a data race on:
     - `dst` / `byteSliceWriter.b`,
     - possibly `src` / `p`,
     - internal writer state.
   - It can also cause:
     - incomplete compressed output,
     - corrupted compressed output,
     - lost write errors,
     - incorrect returned byte count.
   - This is especially important because `AppendBrotliBytesLevel` is a public API that returns the final buffer.

4. **Incorrect returned byte count for non-blocking writers**
   - For the non-blocking writer cases, `WriteBrotliLevel` returns:
     ```go
     return len(p), nil
     ```
   - The documentation says the function returns “the number of compressed bytes written to `w`”.
   - `len(p)` is the **uncompressed input length**, not the compressed output length.
   - If a caller uses this return value to set `Content-Length`, manage response buffers, or perform protocol framing, it may produce incorrect lengths or protocol desynchronization.
   - This is lower severity than the previous issues, but it is still a public API correctness problem with security relevance.

## Areas reviewed and deprioritized

- **Pool type assertions** such as `v.(*brotli.Reader)`, `v.(*brotli.Writer)`, and `v.(stackless.Writer)` are internal. The pools are only populated by internal release functions, so they are not directly attacker-controllable.
- **Nil `p` or nil `dst`** are mostly safe:
  - `p == nil` compresses/decompresses empty input.
  - `dst == nil` works with `byteSliceWriter` because `append` can start from `nil`.
- **Nil `w`** can panic, but that is primarily a caller-error issue rather than a typical untrusted-data issue.
- **Ignored compression errors** in `nonblockingWriteBrotli` are real, but for the specific non-blocking writer types used here the practical impact is mostly correctness/data-race related rather than a direct memory-safety bug.
- There are **no fixed-size stack buffers** in this file, so there is no classic C-style buffer overflow.

```json
[
  {
    "severity": "high",
    "title": "Unbounded brotli decompression can exhaust memory",
    "function": "WriteUnbrotli",
    "description": "WriteUnbrotli calls writeUnbrotli with maxBodySize=0, and writeUnbrotli passes that value to copyZeroAllocWithLimit. In fasthttp, 0 normally disables the limit, so an attacker-controlled brotli payload can decompress to arbitrarily large output. AppendUnbrotliBytes makes this exploitable as a decompression bomb because it appends the decompressed data to dst without any cap. The int overflow check in writeUnbrotli runs after the copy has already written data and is only effective on 32-bit platforms, so it does not prevent denial of service via memory exhaustion."
  },
  {
    "severity": "medium",
    "title": "Out-of-range compression level is passed to brotli.NewWriterLevel and pooled under a normalized key",
    "function": "acquireRealBrotliWriter",
    "description": "WriteBrotliLevel and AppendBrotliBytesLevel accept an arbitrary int level. normalizeBrotliCompressLevel only bounds the value for pool indexing, but acquireRealBrotliWriter passes the original level to brotli.NewWriterLevel. If the brotli dependency expects levels in [0..11], values such as -1 or 12 can cause a panic in the host process. Even if the dependency clamps the level, writers created with out-of-range levels are stored under the normalized default pool bucket, and Reset does not change their configured level. Later legitimate requests for the default level can reuse a writer configured for a different level, causing incorrect compression behavior or further undefined behavior."
  },
  {
    "severity": "high",
    "title": "Ignored stackless deferred-execution return value can cause a data race in brotli compression",
    "function": "stacklessWriteBrotli",
    "description": "stacklessWriteBrotli ignores the bool returned by stacklessWriteBrotliFunc. In the fasthttp stackless runtime, this return value indicates whether nonblockingWriteBrotli executed synchronously in the current goroutine or was deferred to another goroutine. If execution is deferred, WriteBrotliLevel returns len(p), nil and AppendBrotliBytesLevel returns dst before the compressed bytes have been written. This creates a data race on dst/src and internal writer state, can return incomplete or corrupted compressed output, and hides write errors. The race is reachable when compression is invoked with a stack near the limit or from a deep call stack."
  },
  {
    "severity": "low",
    "title": "WriteBrotliLevel returns uncompressed input length instead of compressed byte count for non-blocking writers",
    "function": "WriteBrotliLevel",
    "description": "For *byteSliceWriter, *bytes.Buffer, and *bytebufferpool.ByteBuffer, WriteBrotliLevel returns len(p), nil. That value is the uncompressed input length, not the number of compressed bytes written to the writer, contrary to the documented contract. Callers that use the returned value to set Content-Length, manage response buffers, or perform protocol framing may produce incorrect lengths or misuse memory, which can lead to protocol desynchronization or resource handling bugs."
  }
]
```