BudgetScan

Reset may invoke malicious or invalid io.Closer values

medium swesweep-fasthttp · userdata.go · Reset() · run #4

Description

Reset iterates over stored user values and calls Close() on any value implementing io.Closer. If an application stores attacker-influenced values, or typed nil pointers whose pointer type implements io.Closer, Close may panic, perform unintended side effects, or leave the userData slice in an inconsistent state. Error return values from Close are also ignored.

Triage

Verdict
INVALID confidence 0.0
Model
qwen/qwen3.8-27b
Rounds
5
Cost
$0.0184 · 150.9 s
The report claims that `userData.Reset` is vulnerable because it calls `Close()` on values implementing `io.Closer`, potentially allowing an attacker to inject malicious closers or trigger panics via typed nils. 

1. **Bug Pattern Existence**: The code in `userData.Reset` does indeed iterate through stored values and call `Close()` if they implement `io.Closer`. It does not ignore errors, but a panic in `Close` would propagate. The pattern described exists in the code.

2. **Attacker Reachability**: The threat model for a library defines the attacker as code calling the public API or data passed through it. `userData` is an internal structure that is populated *only* by explicit calls to `SetUserValue` or `SetUserValueBytes` by the host application. The fasthttp library itself does not automatically parse raw network input (HTTP headers, bodies, etc.) into `io.Closer` objects and store them in `userData`. 
   - For an external attacker to trigger this, they would need to cause the host application to construct a malicious `io.Closer` object (e.g., a struct with a `Close` method that panics or performs side effects) and store it in `userData`. 
   - This requires the host application to have a logic flaw: blindly storing attacker-influenced data as complex objects or constructing objects from untrusted input in a way that allows arbitrary code execution or logic manipulation within the application's own code. 
   - If the host application stores a valid `io.Closer` (like a `http.Request` or a custom resource) based on attacker input, the object itself is trusted by the application's logic. A panic in `Close` would be a bug in the object's implementation or the application's failure to handle errors, not a vulnerability in the library's `Reset` method.
   - The library cannot distinguish between a 'valid' Closer and a 'malicious' one because `io.Closer` is a standard interface. The responsibility for providing safe objects lies with the application (trusted code).

3. **Threat Model Compliance**: The threat model states that 'misuse that violates a documented precondition of the public API' is not a vulnerability. Storing an object that causes a panic when `Close` is called is effectively a misuse or a bug in the object, not a flaw in the library's memory safety or integrity. The library is correctly performing cleanup on user-provided interfaces. There is no path for an external attacker to directly influence the `userData` slice contents without the explicit cooperation of the host application's code. Thus, the issue is not reachable by an external attacker through untrusted input alone; it requires a pre-existing vulnerability or logic error in the host application.

4. **Conclusion**: Since the library does not auto-populate `userData` with attacker-controlled `io.Closer` instances, and the values must be explicitly set by trusted application code, this is not a security vulnerability in the library under the given threat model. It is a code quality or application misuse issue.

CRUX: Whether userData values are populated automatically by the library from untrusted network input or only via explicit application calls to SetUserValue.
GREP: SetUserValue
All rounds
[
  {
    "finding_title": "Reset may invoke malicious or invalid io.Closer values",
    "verdict": "INVALID",
    "reasoning": "The report claims that `Reset` in `userData` is vulnerable because it calls `Close()` on any value implementing `io.Closer`, which could panic or cause side effects if the value is malicious or a typed nil. However, `userData` is an internal, unexported type in the `fasthttp` package. The public API surface consists of methods on `Request` and `Response` such as `SetUserValue` and `ResetUserValue` (which calls `Reset`). In the threat model for a library, the attacker is defined as code calling the public API or data passed through it. For a 'malicious or invalid' value to be stored in `userData`, the application (trusted code) must explicitly call `SetUserValue` with that value. An external attacker sending HTTP requests cannot directly inject values into `userData`; they can only influence the keys/values if the application logic parses the request and stores that data. If the application stores untrusted data in `userData`, that is a flaw in the application's logic, not a vulnerability in the library's `Reset` method itself. The library's responsibility is to manage the lifecycle of values it stores. Calling `Close()` on `io.Closer` values is standard cleanup behavior. A panic in `Close` would be due to a bug in the object provided by the application, not a memory safety issue in the library. Furthermore, the 'typed nil pointer' concern: if an application stores a typed nil pointer to an interface that implements `io.Closer`, `Reset` will call `Close`. If the `Close` method on that pointer type dereferences the nil pointer, it panics. This is a 'garbage in, garbage out' scenario where the application passed a bad object. It does not lead to memory corruption in the library, only a panic in the application's process, which is not a security vulnerability for the library itself (it's a reliability issue for the app). More importantly, without a specific demonstration that a standard HTTP parser in fasthttp automatically populates `userData` with attacker-controlled `io.Closer` interfaces (which it doesn't; `userData` is empty by default and only populated via explicit API calls), this is not an external attacker reachable bug. The bug pattern (calling Close on untrusted values) is not really 'malicious' in the sense of memory corruption; it's just standard Go behavior. Since the values must be explicitly set by the host application, and the host application is trusted in the library threat model, this is INVALID.\n\nCRUX: Whether `userData` values are populated automatically from untrusted HTTP input or only via explicit application calls to `SetUserValue`.\nGREP: SetUserValue",
    "elapsed": 34.7,
    "tokens": 3035,
    "tokens_in": 2463,
    "tokens_out": 572,
    "cost_usd": 0.00275046,
    "file": "userdata.go",
    "round": 1,
    "grep_used": true,
    "grep_results": "GREP `SetUserValue`:\n```\nfasthttpadaptor/adaptor_test.go:199:\t\tctx.SetUserValue(key, value)\nserver_test.go:1859:\t\tctx.SetUserValue(k, i)\nserver_test.go:1863:\t\tctx.SetUserValueBytes([]byte(k), i)\nserver_test.go:2691:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver_test.go:2790:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver.go:769:// SetUserValue stores the given value (arbitrary object)\nserver.go:780:func (ctx *RequestCtx) SetUserValue(key, value any) {\nserver.go:781:\tctx.Request.SetUserValue(key, value)\nserver.go:784:// SetUserValueBytes stores the given value (arbitrary object)\nserver.go:793:func (ctx *RequestCtx) SetUserValueBytes(key []byte, value any) {\nserver.go:794:\tctx.Request.SetUserValueBytes(key, value)\nserver.go:797:// UserValue returns the value stored via SetUserValue* under the given key.\nserver.go:802:// UserValueBytes returns the value stored via SetUserValue*\nhttp.go:2295:// SetUserValue stores the given value (arbitrary object)\nhttp.go:2306:func (req *Request) SetUserValue(key, value any) {\nhttp.go:2310:// SetUserValueBytes stores the given value (arbitrary object)\nhttp.go:2319:func (req *Request) SetUserValueBytes(key []byte, value any) {\nhttp.go:2323:// UserValue returns the value stored via SetUserValue* under the given key.\nhttp.go:2328:// UserValueBytes returns the value stored via SetUserValue*\n```"
  },
  {
    "finding_title": "Reset may invoke malicious or invalid io.Closer values",
    "verdict": "INVALID",
    "reasoning": "The vulnerability report claims that `userData.Reset` is vulnerable to malicious `io.Closer` values causing panics or side effects. However, under the binding threat model for a library, the attacker is defined as 'Code that calls the public API, and above all the data it passes through: parsers, decoders, deserializers and protocol handlers receive adversarial payloads'. The `userData` structure is populated exclusively via explicit API calls (`SetUserValue`, `SetUserValueBytes`) by the host application. The attacker (external entity sending HTTP requests) cannot directly insert arbitrary objects into `userData`; they can only influence the *keys* and *values* if the *application* chooses to parse attacker-controlled data (like headers or bodies) and store that data in `userData`. \n\n1. **Attacker Reachability**: For an attacker to trigger a malicious `io.Closer` in `Reset`, the host application must parse untrusted input, create an object implementing `io.Closer` that behaves maliciously (e.g., panics on `Close`), and explicitly call `SetUserValue` with that object. This requires the application to have a severe logic flaw (trusting parsed data to construct arbitrary objects). The library itself does not auto-populate `userData` with attacker data. \n2. **Nature of the Bug**: The report cites 'panic' and 'inconsistent state' as impacts. In Go, a panic in `Reset` (triggered by a malicious `Close`) would crash the request handler or goroutine. While crashing is bad, the root cause is the application passing a defective/malicious object. The library's `Reset` method is performing standard cleanup. If the object is 'malicious' (i.e., designed to panic), the attacker must have control over the object creation, which implies they control the application code or the application is blindly constructing objects from untrusted data without validation. \n3. **Library Responsibility**: The library's responsibility is to not corrupt *its own* memory or state. Calling `vc.Close()` on an interface value is safe for the library's memory space; any resulting panic or side effect is a consequence of the value provided by the trusted caller. The threat model explicitly states: 'Not a vulnerability under this model: ... misuse that violates a documented precondition of the public API.' Storing arbitrary untrusted objects in `userData` is effectively misuse if the application intends for those objects to be safe for cleanup. More importantly, the 'attacker' in the library model is the caller, but the impact must be on the library's integrity. Here, the impact is a crash caused by the caller's bad input. This is generally considered a code quality/robustness issue for the application, not a vulnerability in the library itself, unless the library fails to handle *standard* malformed input from its own parsers. Since `userData` is not a parser for HTTP data but a general-purpose bag for app data, it doesn't parse untrusted input directly.\n\nTherefore, the bug is not reachable by an external attacker without a pre-existing, severe vulnerability in the host application's logic (blindly storing untrusted objects). The library code is behaving correctly according to the Go type system and the library threat model.\n\nCRUX: Whether `userData` is populated directly by the library from untrusted network input or only via explicit application calls.\nGREP: SetUserValue",
    "elapsed": 30.7,
    "tokens": 4325,
    "tokens_in": 3607,
    "tokens_out": 718,
    "cost_usd": 0.00366894,
    "file": "userdata.go",
    "round": 2,
    "grep_used": true,
    "grep_results": "GREP `SetUserValue`:\n```\nfasthttpadaptor/adaptor_test.go:199:\t\tctx.SetUserValue(key, value)\nserver_test.go:1859:\t\tctx.SetUserValue(k, i)\nserver_test.go:1863:\t\tctx.SetUserValueBytes([]byte(k), i)\nserver_test.go:2691:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver_test.go:2790:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver.go:769:// SetUserValue stores the given value (arbitrary object)\nserver.go:780:func (ctx *RequestCtx) SetUserValue(key, value any) {\nserver.go:781:\tctx.Request.SetUserValue(key, value)\nserver.go:784:// SetUserValueBytes stores the given value (arbitrary object)\nserver.go:793:func (ctx *RequestCtx) SetUserValueBytes(key []byte, value any) {\nserver.go:794:\tctx.Request.SetUserValueBytes(key, value)\nserver.go:797:// UserValue returns the value stored via SetUserValue* under the given key.\nserver.go:802:// UserValueBytes returns the value stored via SetUserValue*\nhttp.go:2295:// SetUserValue stores the given value (arbitrary object)\nhttp.go:2306:func (req *Request) SetUserValue(key, value any) {\nhttp.go:2310:// SetUserValueBytes stores the given value (arbitrary object)\nhttp.go:2319:func (req *Request) SetUserValueBytes(key []byte, value any) {\nhttp.go:2323:// UserValue returns the value stored via SetUserValue* under the given key.\nhttp.go:2328:// UserValueBytes returns the value stored via SetUserValue*\n```"
  },
  {
    "finding_title": "Reset may invoke malicious or invalid io.Closer values",
    "verdict": "INVALID",
    "reasoning": "The reported vulnerability claims that `userData.Reset` is vulnerable because it calls `Close()` on stored values implementing `io.Closer`. The core question is whether an external attacker can influence the values stored in `userData` to trigger a panic, side effect, or state corruption in `Reset`.\n\n1.  **Trust Boundary Analysis**: The threat model for a library defines the attacker as code calling the public API or data passed through it. `userData` is an internal structure populated exclusively via `Request.SetUserValue` or `RequestCtx.SetUserValue`. These functions accept `any` types for both key and value.\n\n2.  **Attacker Reachability**: For an attacker to inject a malicious `io.Closer` (e.g., an object that panics on `Close` or performs unauthorized network calls), they must cause the *host application* to store such an object in `userData`. The library's standard HTTP parsing routines (`Request.Read`, `parseHeader`, etc.) do not automatically create `io.Closer` objects from raw bytes. They create strings, slices, or simple structs. An attacker sending raw HTTP data cannot directly instantiate a Go interface implementation with a specific `Close` method unless the host application explicitly parses that data, allocates a new object, implements `io.Closer` (or uses a standard library object like a `File` or `NetConn` derived from the request), and calls `SetUserValue`.\n\n3.  **Nature of the 'Vulnerability'**: Even if the application blindly stored an attacker-influenced object, the panic or side effect occurs within the application's control flow when `Close` is called. The library's `Reset` function is performing standard cleanup. A panic in `Close` is a failure of the object provided by the application, not a memory safety failure of the library. The library does not corrupt its own memory; it simply invokes a method on a user-provided interface. If the user provides a buggy or malicious object, the resulting crash is a consequence of the application's logic flaw (storing untrusted/invalid objects), not a vulnerability in the library's `Reset` implementation. The library cannot distinguish between a 'valid' Closer and a 'malicious' one because `io.Closer` is an opaque interface.\n\n4.  **Defense/Absence thereof**: There is no validation in `SetUserValue` because it accepts `any`. However, this is by design for a general-purpose user data store. The 'bug' is effectively 'what happens if you store a bad object,' which is a misuse of the API or an application-level vulnerability, not a library security vulnerability. The library's responsibility is to manage the lifecycle of values it knows about or to provide a mechanism for the app to manage them. It does not guarantee that arbitrary user-provided interfaces are safe to call. Since the attacker cannot bypass the application layer to inject the interface implementation directly, the attack vector is not valid under the library threat model.\n\n5.  **Conclusion**: The bug pattern (calling Close on untrusted values) exists in the code, but the input (the value) is not directly attacker-controlled via untrusted network input. It requires the host application to explicitly construct and store the value. Therefore, it is not an external attacker-reachable vulnerability in the library itself.\n\nCRUX: Whether the library automatically populates userData with attacker-controlled io.Closer instances from raw network input, or if this requires explicit application logic that falls outside the library's trust boundary.\nGREP: SetUserValue",
    "elapsed": 27.2,
    "tokens": 5149,
    "tokens_in": 4396,
    "tokens_out": 753,
    "cost_usd": 0.00410532,
    "file": "userdata.go",
    "round": 3,
    "grep_used": true,
    "grep_results": "GREP `SetUserValue`:\n```\nfasthttpadaptor/adaptor_test.go:199:\t\tctx.SetUserValue(key, value)\nserver_test.go:1859:\t\tctx.SetUserValue(k, i)\nserver_test.go:1863:\t\tctx.SetUserValueBytes([]byte(k), i)\nserver_test.go:2691:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver_test.go:2790:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver.go:769:// SetUserValue stores the given value (arbitrary object)\nserver.go:780:func (ctx *RequestCtx) SetUserValue(key, value any) {\nserver.go:781:\tctx.Request.SetUserValue(key, value)\nserver.go:784:// SetUserValueBytes stores the given value (arbitrary object)\nserver.go:793:func (ctx *RequestCtx) SetUserValueBytes(key []byte, value any) {\nserver.go:794:\tctx.Request.SetUserValueBytes(key, value)\nserver.go:797:// UserValue returns the value stored via SetUserValue* under the given key.\nserver.go:802:// UserValueBytes returns the value stored via SetUserValue*\nhttp.go:2295:// SetUserValue stores the given value (arbitrary object)\nhttp.go:2306:func (req *Request) SetUserValue(key, value any) {\nhttp.go:2310:// SetUserValueBytes stores the given value (arbitrary object)\nhttp.go:2319:func (req *Request) SetUserValueBytes(key []byte, value any) {\nhttp.go:2323:// UserValue returns the value stored via SetUserValue* under the given key.\nhttp.go:2328:// UserValueBytes returns the value stored via SetUserValue*\n```"
  },
  {
    "finding_title": "Reset may invoke malicious or invalid io.Closer values",
    "verdict": "INVALID",
    "reasoning": "The report claims that `Reset` is vulnerable because it calls `Close()` on `io.Closer` values, which could panic or cause side effects if the value is malicious or invalid. Under the provided threat model for a reusable library, the 'attacker' is code calling the public API or untrusted data passing through it. The `userData` structure is populated exclusively via explicit calls to `SetUserValue` or `SetUserValueBytes` by the host application. The library's internal HTTP parsing logic does not automatically instantiate or store `io.Closer` objects in `userData` based on raw network input. Therefore, for an external attacker to trigger this 'vulnerability', they would need to induce the host application (trusted code) to parse untrusted data, construct an object implementing `io.Closer` that behaves maliciously (e.g., panics on `Close`), and explicitly store it in `userData`. This constitutes a flaw in the application's logic (misuse of the library API) rather than a vulnerability in the library itself. The library is performing standard cleanup on user-provided interfaces. A panic in `Close` is a consequence of the application providing a defective object, not a memory safety failure or security bypass in the library. Since the attacker cannot directly control the values stored in `userData` without a pre-existing, severe vulnerability in the host application, the issue is not attacker-reachable through the library's public surface in the way defined by the threat model. It is a code quality/robustness issue (or application misuse) rather than a security vulnerability in the library.\n\nCRUX: The userData values are only populated via explicit application calls to SetUserValue, not automatically by the library from untrusted network input, making the 'malicious value' scenario dependent on application logic flaws rather than direct attacker control.\nGREP: SetUserValue",
    "elapsed": 28.3,
    "tokens": 5616,
    "tokens_in": 5218,
    "tokens_out": 398,
    "cost_usd": 0.00338556,
    "file": "userdata.go",
    "round": 4,
    "grep_used": true,
    "grep_results": "GREP `SetUserValue`:\n```\nfasthttpadaptor/adaptor_test.go:199:\t\tctx.SetUserValue(key, value)\nserver_test.go:1859:\t\tctx.SetUserValue(k, i)\nserver_test.go:1863:\t\tctx.SetUserValueBytes([]byte(k), i)\nserver_test.go:2691:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver_test.go:2790:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver.go:769:// SetUserValue stores the given value (arbitrary object)\nserver.go:780:func (ctx *RequestCtx) SetUserValue(key, value any) {\nserver.go:781:\tctx.Request.SetUserValue(key, value)\nserver.go:784:// SetUserValueBytes stores the given value (arbitrary object)\nserver.go:793:func (ctx *RequestCtx) SetUserValueBytes(key []byte, value any) {\nserver.go:794:\tctx.Request.SetUserValueBytes(key, value)\nserver.go:797:// UserValue returns the value stored via SetUserValue* under the given key.\nserver.go:802:// UserValueBytes returns the value stored via SetUserValue*\nhttp.go:2295:// SetUserValue stores the given value (arbitrary object)\nhttp.go:2306:func (req *Request) SetUserValue(key, value any) {\nhttp.go:2310:// SetUserValueBytes stores the given value (arbitrary object)\nhttp.go:2319:func (req *Request) SetUserValueBytes(key []byte, value any) {\nhttp.go:2323:// UserValue returns the value stored via SetUserValue* under the given key.\nhttp.go:2328:// UserValueBytes returns the value stored via SetUserValue*\n```"
  },
  {
    "finding_title": "Reset may invoke malicious or invalid io.Closer values",
    "verdict": "INVALID",
    "reasoning": "The report claims that `userData.Reset` is vulnerable because it calls `Close()` on values implementing `io.Closer`, potentially allowing an attacker to inject malicious closers or trigger panics via typed nils. \n\n1. **Bug Pattern Existence**: The code in `userData.Reset` does indeed iterate through stored values and call `Close()` if they implement `io.Closer`. It does not ignore errors, but a panic in `Close` would propagate. The pattern described exists in the code.\n\n2. **Attacker Reachability**: The threat model for a library defines the attacker as code calling the public API or data passed through it. `userData` is an internal structure that is populated *only* by explicit calls to `SetUserValue` or `SetUserValueBytes` by the host application. The fasthttp library itself does not automatically parse raw network input (HTTP headers, bodies, etc.) into `io.Closer` objects and store them in `userData`. \n   - For an external attacker to trigger this, they would need to cause the host application to construct a malicious `io.Closer` object (e.g., a struct with a `Close` method that panics or performs side effects) and store it in `userData`. \n   - This requires the host application to have a logic flaw: blindly storing attacker-influenced data as complex objects or constructing objects from untrusted input in a way that allows arbitrary code execution or logic manipulation within the application's own code. \n   - If the host application stores a valid `io.Closer` (like a `http.Request` or a custom resource) based on attacker input, the object itself is trusted by the application's logic. A panic in `Close` would be a bug in the object's implementation or the application's failure to handle errors, not a vulnerability in the library's `Reset` method.\n   - The library cannot distinguish between a 'valid' Closer and a 'malicious' one because `io.Closer` is a standard interface. The responsibility for providing safe objects lies with the application (trusted code).\n\n3. **Threat Model Compliance**: The threat model states that 'misuse that violates a documented precondition of the public API' is not a vulnerability. Storing an object that causes a panic when `Close` is called is effectively a misuse or a bug in the object, not a flaw in the library's memory safety or integrity. The library is correctly performing cleanup on user-provided interfaces. There is no path for an external attacker to directly influence the `userData` slice contents without the explicit cooperation of the host application's code. Thus, the issue is not reachable by an external attacker through untrusted input alone; it requires a pre-existing vulnerability or logic error in the host application.\n\n4. **Conclusion**: Since the library does not auto-populate `userData` with attacker-controlled `io.Closer` instances, and the values must be explicitly set by trusted application code, this is not a security vulnerability in the library under the given threat model. It is a code quality or application misuse issue.\n\nCRUX: Whether userData values are populated automatically by the library from untrusted network input or only via explicit application calls to SetUserValue.\nGREP: SetUserValue",
    "elapsed": 30.0,
    "tokens": 6384,
    "tokens_in": 5692,
    "tokens_out": 692,
    "cost_usd": 0.00446664,
    "file": "userdata.go",
    "round": 5,
    "grep_used": true,
    "grep_results": "GREP `SetUserValue`:\n```\nfasthttpadaptor/adaptor_test.go:199:\t\tctx.SetUserValue(key, value)\nserver_test.go:1859:\t\tctx.SetUserValue(k, i)\nserver_test.go:1863:\t\tctx.SetUserValueBytes([]byte(k), i)\nserver_test.go:2691:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver_test.go:2790:\t\t\tctx.SetUserValue(\"myKey\", &closerWithRequestCtx{\nserver.go:769:// SetUserValue stores the given value (arbitrary object)\nserver.go:780:func (ctx *RequestCtx) SetUserValue(key, value any) {\nserver.go:781:\tctx.Request.SetUserValue(key, value)\nserver.go:784:// SetUserValueBytes stores the given value (arbitrary object)\nserver.go:793:func (ctx *RequestCtx) SetUserValueBytes(key []byte, value any) {\nserver.go:794:\tctx.Request.SetUserValueBytes(key, value)\nserver.go:797:// UserValue returns the value stored via SetUserValue* under the given key.\nserver.go:802:// UserValueBytes returns the value stored via SetUserValue*\nhttp.go:2295:// SetUserValue stores the given value (arbitrary object)\nhttp.go:2306:func (req *Request) SetUserValue(key, value any) {\nhttp.go:2310:// SetUserValueBytes stores the given value (arbitrary object)\nhttp.go:2319:func (req *Request) SetUserValueBytes(key []byte, value any) {\nhttp.go:2323:// UserValue returns the value stored via SetUserValue* under the given key.\nhttp.go:2328:// UserValueBytes returns the value stored via SetUserValue*\n```"
  }
]
Raw scan report for this file

`userData` is an unexported per-request/response key/value store, but it is reachable through exported `Request`/`Response`/`RequestCtx` user-value APIs. The main risk is not classic memory corruption, but availability and state corruption caused by unvalidated `any` keys, uncontrolled resource lifecycle, and unbounded growth.

Key observations:

- `Set`, `Get`, and `Remove` compare `kv.key == key`, where both values are `any`. If the dynamic type is uncomparable, such as a slice, map, function, or a struct containing any of those, the comparison panics.
- `Set` normalizes exact `[]byte` keys to `string`, but it does not reject or normalize other uncomparable key types.
- `Get` and `Remove` use `b2s` for `[]byte` keys. That is usually safe in this context because the converted string is only used for comparison and is not stored, but it depends on `b2s` behaving as expected.
- `Reset` calls `Close()` on any user value implementing `io.Closer`. If a stored value is attacker-influenced or a typed nil pointer implementing `io.Closer`, cleanup can panic or leak state.
- There is no bound on the number of user values, and lookup is linear, so an application that stores many attacker-influenced keys can be made to allocate excessive memory or spend excessive CPU.

```json
[
  {
    "severity": "High",
    "title": "Panic from comparing uncomparable any keys",
    "function": "Set()/Get()/Remove()",
    "description": "The code compares interface values with kv.key == key without verifying that the dynamic key type is comparable. If a caller stores or looks up a key whose dynamic type is a slice, map, function, or a struct containing an uncomparable field, Go panics at runtime. This is reachable through public user-value APIs that accept key as any, and can be used to cause denial of service if an attacker can influence the key object passed to the application."
  },
  {
    "severity": "Medium",
    "title": "Reset may invoke malicious or invalid io.Closer values",
    "function": "Reset()",
    "description": "Reset iterates over stored user values and calls Close() on any value implementing io.Closer. If an application stores attacker-influenced values, or typed nil pointers whose pointer type implements io.Closer, Close may panic, perform unintended side effects, or leave the userData slice in an inconsistent state. Error return values from Close are also ignored."
  },
  {
    "severity": "Low",
    "title": "Replacing or clearing a Closer user value without closing it",
    "function": "Set()",
    "description": "Set overwrites an existing value with the new value, including nil, without checking whether the old value implements io.Closer. If an application uses Set(key, nil) or Set(key, other) to replace a resource-holding value, the old resource is not closed, leading to resource leaks."
  },
  {
    "severity": "Low",
    "title": "Unbounded user-value storage and linear lookup",
    "function": "Set()",
    "description": "userData has no limit on the number of entries, and Get/Remove perform linear scans. If a host application stores attacker-influenced keys, such as parsed body fields or generated identifiers, without validation or limits, an attacker can cause excessive memory allocation or CPU consumption."
  }
]
```