BudgetScan

Raw expvar values inserted into JSON response without validation

low swesweep-fasthttp · expvarhandler/expvar.go · ExpvarHandler · run #4

Description

kv.Value is inserted directly into the JSON response without validating that it is a well-formed JSON value. If a registered expvar produces a non-JSON string or a value influenced by untrusted input, the response can become malformed or allow JSON field injection into clients that parse it.

Triage

Not triaged.

Raw scan report for this file

The file is a small fasthttp handler whose only external input is the HTTP query argument `r`. The data flow is:

1. `ExpvarHandler` is called by fasthttp for each request.
2. `getExpvarRegexp` reads `r` from the query string.
3. If `r` is empty, the built-in regex `.` is used, which matches all non-empty expvar keys.
4. If `r` is non-empty, it is compiled directly with `regexp.Compile`.
5. `ExpvarHandler` iterates over all registered expvars using `expvar.Do`, filters keys with the compiled regex, and writes the matched values into an HTTP response.

There are no fixed-size C-style buffers, numeric size constants, or integer overflow paths. The main risks are resource exhaustion, information disclosure, and weak JSON serialization assumptions.

Findings:

- `getExpvarRegexp` accepts an arbitrary regex from the network and compiles it with no length, complexity, or time limit. Go’s RE2 engine avoids exponential backtracking ReDoS, but compilation and automaton construction can still consume significant CPU and memory. An attacker can send very large or complex `r` values to degrade the service.
- `ExpvarHandler` exposes all registered expvars by default and does not perform authentication, authorization, or rate limiting. If the handler is mounted on an externally reachable endpoint, untrusted users can read any expvar registered by the host application.
- `ExpvarHandler` has no bound on the number or size of expvars emitted. If the host registers many variables or variables whose values are large, a request can cause large response allocation and CPU work.
- `ExpvarHandler` inserts `kv.Value` directly into the JSON response. If any registered expvar produces a string that is not a valid JSON value, or if a value is influenced by untrusted input elsewhere, the response may be malformed or allow JSON field injection into consuming clients.

Lower-priority observations not included as findings:

- `ctx` nil would panic, but that is a caller error, not something an external attacker can trigger through the HTTP request surface.
- The error path reflects the user-supplied `r` value in the response. This is input reflection, but fasthttp typically serves safe default content types; this is less impactful than the resource and disclosure issues.
- Write errors from `fmt.Fprintf(ctx, ...)` are ignored, which is common for HTTP response writers and not a direct vulnerability.

```json
[
  {
    "severity": "medium",
    "title": "Uncontrolled regular expression compilation from r query argument",
    "function": "getExpvarRegexp",
    "description": "The r query argument is converted to a string and passed to regexp.Compile with no length, complexity, or timeout limit. An attacker can send large or crafted patterns to consume CPU and memory, causing denial of service. Go RE2 avoids exponential backtracking, but compilation and automaton construction can still be expensive."
  },
  {
    "severity": "medium",
    "title": "Unauthenticated exposure of all registered expvars",
    "function": "ExpvarHandler",
    "description": "ExpvarHandler serves all registered expvars by default and does not enforce authentication, authorization, or rate limiting. If the handler is mounted on a network-facing endpoint, an unauthenticated attacker can read host metrics or any custom expvars, including potentially sensitive operational data."
  },
  {
    "severity": "low",
    "title": "Unbounded expvar response generation",
    "function": "ExpvarHandler",
    "description": "There is no cap on the number of expvars or the size of their serialized values. expvar.Do iterates every variable and fmt.Fprintf writes all matched values into the response buffer. Numerous or large variables can cause unbounded memory allocation and CPU use per request."
  },
  {
    "severity": "low",
    "title": "Raw expvar values inserted into JSON response without validation",
    "function": "ExpvarHandler",
    "description": "kv.Value is inserted directly into the JSON response without validating that it is a well-formed JSON value. If a registered expvar produces a non-JSON string or a value influenced by untrusted input, the response can become malformed or allow JSON field injection into clients that parse it."
  }
]
```