GoFr — Auth middleware exempts the entire /.well-known prefix, leading to authentication bypass
- Dominant language
- Go
- Stars
- 20.9k
- Forks
- 1.8k
- Avg merge
- 5d 18h
- Merged PRs (30d)
- 39
Description
# GoFr — Authentication bypass via /.well-known prefix exemption in AuthMiddleware leads to anonymous access to protected routes and health data
## Summary
GoFr's unified authentication middleware (`AuthMiddleware`) calls `isWellKnown(r.URL.Path)` before extracting any authentication header, and `isWellKnown` is implemented as `strings.HasPrefix(path, "/.well-known")`. This exempts the entire `/.well-known` prefix — not just an intended probe path — so the built-in `/.well-known/health` endpoint (which the official documentation acknowledges may expose dependency service hosts and statistics) remains anonymously reachable even after Basic Auth, API Key, or OAuth is enabled. In addition, any user-registered route whose path merely starts with `/.well-known` (e.g. `/.well-knownprivate` — no slash is required to match the prefix) silently skips authentication, and because the same `isWellKnown` check is reused by the rate limiter, these paths bypass rate limiting as well.
**Weakness:** CWE-306: Missing Authentication for Critical Function (secondary: CWE-200: Exposure of Sensitive Information)
## Root Cause
In GoFr v1.58.0:
1. `pkg/gofr/http/middleware/validate.go:5-7` — `isWellKnown` is implemented as `strings.HasPrefix(path, "/.well-known")`. It is a raw prefix match that does not require the prefix to be followed by `/`, so paths such as `/.well-knownprivate` also match.
2. `pkg/gofr/http/middleware/auth.go:49-52` — `AuthMiddleware` evaluates `isWellKnown(r.URL.Path)` before `ExtractAuthHeader` and, on a match, passes the request directly to `handler.ServeHTTP`, skipping authentication entirely. All official auth mechanisms (Basic Auth, API Key, OAuth) share this middleware, so every one of them is bypassed for matching paths.
3. `pkg/gofr/http/middleware/rate_limiter.go:133-136` — the same `isWellKnown` check is reused in the rate limiter, so matching paths also skip rate limiting.
## Impact
- An anonymous attacker can read the built-in `/.well-known/health` endpoint of applications that have authentication enabled, leaking internal dependency topology (database/cache hosts, status, statistics).
- Developers cannot protect any route under `/.well-known*` using GoFr's official authentication capability; business routes registered with that prefix — knowingly or unknowingly — are exposed directly.
- Matching paths additionally bypass the rate limiter, removing throttling protection from those endpoints.
## Prerequisites
- Anonymous network access to a GoFr application that has any official authentication enabled (Basic Auth, API Key, or OAuth). No account or credentials are needed.
- For the health-data disclosure: the application serves the built-in `/.well-known/health` endpoint (framework default).
- For the custom-route bypass: the application has registered at least one route whose path starts with `/.well-known`.
## Steps to Reproduce
1. Using a Go toolchain, create the application from the Proof of Concept code below: a GoFr app with API Key authentication enabled, registering `GET /protected` and `GET /.well-knownprivate`.
2. Run the application (it listens on port 8000 by default).
3. Request the ordinary protected route without credentials: `curl -i http://localhost:8000/protected` — observe `401 Unauthorized`.
4. Request the registered route that starts with `/.well-known` without credentials: `curl -i http://localhost:8000/.well-knownprivate` — observe `200` with the body `SHOULD-BE-PROTECTED`: authentication is bypassed by the prefix exemption.
5. Request the built-in health endpoint without credentials: `curl -i http://localhost:8000/.well-known/health` — observe `200` with dependency information returned anonymously.
## Proof of Concept
The following self-contained program demonstrates the bypass. Running it requires a Go toolchain; the behavior was verified by source-code review of the middleware chain. Basic Auth and OAuth are affected identically, since all auth methods share `AuthMiddleware`.
```go
// GoFr authentication bypass PoC — gofr v1.58.0
package main
import (
"gofr.dev/pkg/gofr"
)
func main() {
app := gofr.New()
// Enable official API Key auth (Basic/OAuth are affected as well — they share AuthMiddleware)
app.EnableAPIKeyAuth("my-secret-key")
app.GET("/protected", func(ctx *gofr.Context) (any, error) {
return "PROTECTED-DATA", nil
})
// Note: no slash needed — "/.well-knownprivate" still matches HasPrefix("/.well-known")
app.GET("/.well-knownprivate", func(ctx *gofr.Context) (any, error) {
return "SHOULD-BE-PROTECTED", nil
})
app.Run()
}
// Reproduce:
// curl -i http://localhost:8000/protected -> 401
// curl -i http://localhost:8000/.well-knownprivate -> 200 SHOULD-BE-PROTECTED (authentication bypass)
// curl -i http://localhost:8000/.well-known/health -> 200 (dependency info anonymously readable)
```
## Evidence
Source-code evidence (GoFr v1.58.0; the identical code path is also present on main @ commit 3e1265c3a4 — both checked 2026-07-21):
- `pkg/gofr/http/middleware/validate.go:5-7` — the exemption predicate is a plain prefix match with no `/` boundary requirement:
`isWellKnown` = `strings.HasPrefix(path, "/.well-known")`
- `pkg/gofr/http/middleware/auth.go:49-52` — on a prefix match, `AuthMiddleware` hands the request directly to `handler.ServeHTTP` before ever invoking `ExtractAuthHeader`, so no authentication mechanism is applied to matching paths.
- `pkg/gofr/http/middleware/rate_limiter.go:133-136` — the same prefix check causes matching paths to skip rate limiting.
Vendor corroboration (public):
- Issue #2550 was labeled a bug by the maintainers, who stated that only `alive` should be public and that `health`, which contains database information, should not be.
- PR #2565 attempted to narrow the exemption but was closed for compatibility reasons.
- Issue #2562 again confirmed the full-prefix bypass behavior.
## Affected Version
Verified on GoFr v1.58.0 and on main @ commit 3e1265c3a4 (both checked 2026-07-21); the code path is still present in the latest version.
## CVSS
**CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N — 5.3 (Medium)**
- AV:N — exploitable over the network with plain HTTP requests.
- AC:L — no special conditions; the bypass is decided by a simple string-prefix check.
- PR:N — no credentials or prior authentication required.
- UI:N — no user interaction is needed.
- S:U — impact is confined to the vulnerable application itself.
- C:L — anonymous read access to dependency/health information and to routes that should be protected; limited confidentiality loss.
- I:N — no integrity impact.
- A:N — no availability impact.
## Remediation
1. Change `isWellKnown` from prefix matching to exact-path matching, exempting only `/.well-known/alive` (or an explicit allowlist of safe paths).
2. Bring `/.well-known/health` under authentication by default, or provide an explicit configuration switch for exposing it.
3. Add regression tests asserting that an unauthenticated request to a prefixed route such as `/.well-knownprivate` returns 401.
## References
- https://gofr.dev/docs/advanced-guide/authentication
- https://github.com/gofr-dev/gofr/issues/2550
- https://github.com/gofr-dev/gofr/pull/2565
- https://github.com/gofr-dev/gofr/issues/2562
Contributor guide
Research direction
Start by reading pkg/gofr/http/middleware/validate.go, auth.go, and rate_limiter.go, then run the Go proof of concept to observe authentication and rate-limit bypasses. Check the existing well-known endpoint behavior and add regression coverage for /.well-knownprivate and /.well-known/health; done means only the intended public path remains exempt and protected prefixed routes require authentication.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- authentication, backend, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100