Unauthenticated /stats endpoint exposes expvar statistics
low swesweep-fasthttp · examples/fileserver/fileserver.go · requestHandler · run #4
Description
Any client can request /stats, which is handled by expvarhandler.ExpvarHandler with no authentication or rate limiting. The current expvars only expose request counters, but the endpoint can aid reconnaissance and may leak additional statistics if more expvars are registered in a deployment. Restrict /stats to trusted networks or disable it in production.
Triage
Not triaged.
Raw scan report for this file
This file is an example static file server. The direct attack surface is the HTTP request, specifically the request path, `Host` header, and query arguments when `/stats` is requested. Most of the input handling is delegated to `fasthttp` and `expvarhandler`, so the local code itself does not perform explicit parsing of untrusted data into fixed buffers or indexes.
### Attack-surface walkthrough
#### `main`
- `flag.Parse()` reads operator-controlled flags. These are not attacker-controlled in the normal threat model, so misconfiguration here is lower priority than network-triggered issues.
- `fasthttp.FS` is configured with `Root`, `IndexNames`, `GenerateIndexPages`, `Compress`, and `AcceptByteRange`.
- If `-vhost` is enabled, `fs.PathRewrite = fasthttp.NewVHostPathRewriter(0)` is set. This causes the request `Host` header to influence the filesystem lookup path. That is the most security-relevant network-controlled flow in this file.
- HTTP and HTTPS listeners are started in goroutines. If `ListenAndServe` or `ListenAndServeTLS` fails, the program calls `log.Fatalf` inside a goroutine. This can terminate the whole process if one listener fails while another is running. That is an availability/configuration issue, not a directly attacker-triggered memory-safety or parsing bug.
- `select {}` blocks forever. If no listener is configured, the program simply does not serve traffic; this is not a remotely exploitable vulnerability.
#### `requestHandler`
- `ctx.Path()` is used to route requests.
- `/stats` is handled by `expvarhandler.ExpvarHandler(ctx)`.
- Everything else is handled by `fsHandler(ctx)`, then `updateFSCounters(ctx)`.
- `string(ctx.Path())` is safe in Go; it copies bytes and does not create a pointer into attacker-controlled memory unsafely.
- The `/stats` endpoint is unauthenticated. The query arguments are passed to `expvarhandler`, so they are attacker-controlled. In this example the exposed expvars are limited to request counters, but the endpoint itself is an information-disclosure surface.
#### `updateFSCounters`
- `resp := &ctx.Response` assumes `ctx` is non-nil. In a fasthttp request handler, `ctx` is provided by the server and should not be nil.
- `resp.Header.ContentLength()` is used only to update an expvar counter.
- If `ContentLength()` is negative or unknown, the counter can be updated with a negative value, but that only affects statistics and is not a memory-safety or exploitable DoS condition.
- The expvar counters are thread-safe.
### Main security-relevant flows
1. **Request path → `fsHandler`**
- This is handled by `fasthttp.FS`. The local file does not perform its own path canonicalization or bounds checking. The safety of path traversal protection depends on `fasthttp`’s implementation.
- If `fasthttp.FS` correctly canonicalizes and confines paths to `Root`, no direct traversal exists from this file.
2. **Request `Host` → `PathRewrite` → filesystem lookup**
- With `-vhost`, `NewVHostPathRewriter(0)` uses the request `Host` header to modify the path served from disk.
- The `Host` header is attacker-controlled.
- This example does not apply an allowlist, normalization, or explicit rejection of traversal-like host values.
- Therefore the security of this flow depends entirely on `fasthttp.NewVHostPathRewriter` safely handling host values and path traversal. If it does not, an attacker could potentially influence the served file path.
3. **Request `/stats` → `expvarhandler.ExpvarHandler`**
- The endpoint is open to all clients.
- The current expvars are limited counters, so the direct impact is low.
- If additional expvars are registered in a deployment, `/stats` could expose more internal state.
### Non-findings / lower-priority issues
- No fixed-size buffer copies are performed in this file.
- No slice or array indexing based on attacker-controlled lengths is performed in this file.
- No integer arithmetic is used in a way that can overflow and become a size or index.
- No tagged union or variant access is performed in this file.
- No command or SQL injection surface is present.
- No direct `unsafe` package usage is present.
- No obvious goroutine deadlock caused by attacker input is present.
- The `log.Fatalf` calls inside listener goroutines are availability/configuration concerns rather than remotely triggered memory-corruption vulnerabilities.
```json
[
{
"severity": "medium",
"title": "Host-header-controlled path rewrite when -vhost is enabled",
"function": "main",
"description": "When the -vhost flag is set, fs.PathRewrite is assigned fasthttp.NewVHostPathRewriter(0). The HTTP Host header is attacker-controlled and is used to modify the filesystem lookup path. This example performs no host allowlisting, normalization, or rejection of traversal-like values. If fasthttp's vhost rewriter does not fully sanitize Host and path, an attacker can influence which file is served and potentially access files outside the intended vhost subtree or Root."
},
{
"severity": "low",
"title": "Directory index generation enabled by default can leak file names",
"function": "main",
"description": "GenerateIndexPages defaults to true. For directories under -dir that do not contain index.html, an attacker can request the directory and receive a generated index listing file names. If the served directory contains non-public data, this enables enumeration and reconnaissance. Consider defaulting index generation to false or restricting it to trusted paths."
},
{
"severity": "low",
"title": "Unauthenticated /stats endpoint exposes expvar statistics",
"function": "requestHandler",
"description": "Any client can request /stats, which is handled by expvarhandler.ExpvarHandler with no authentication or rate limiting. The current expvars only expose request counters, but the endpoint can aid reconnaissance and may leak additional statistics if more expvars are registered in a deployment. Restrict /stats to trusted networks or disable it in production."
}
]
```