GitHub Security Advisory: GHSA-pq96-pwvg-vrr9
Package: github.com/fatedier/frp (GO)
Severity: MODERATE (CVSS 6.5)
CWE: CWE-287: Improper Authentication
Vulnerable versions: >= 0.43.0, <= 0.68.0
Patched in: 0.68.1

Summary: frp has an authentication bypass in HTTP vhost routing when routeByHTTPUser is used for access control

Details:
### Summary
frp contains an authentication bypass in the HTTP vhost routing path when `routeByHTTPUser` is used as part of access control. In proxy-style requests, the routing logic uses the username from `Proxy-Authorization` to select the `routeByHTTPUser` backend, while the access control check uses credentials from the regular `Authorization` header. As a result, an attacker who can reach the HTTP vhost entrypoint and knows or can guess the protected `routeByHTTPUser` value may access a backend protected by `httpUser` / `httpPassword` even with an incorrect `Proxy-Authorization` password.

This issue affects deployments that explicitly use `routeByHTTPUser`. It does not affect ordinary HTTP proxies that do not use this feature.

### Details
The issue is in `pkg/util/vhost/http.go`.

In proxy-style requests using an absolute URI, the routing path extracts the username from `Proxy-Authorization` and stores it as the request `HTTPUser`, which is then used for `routeByHTTPUser` route selection.

More specifically, `injectRequestInfoToCtx()` derives the routing user from `Proxy-Authorization`, while the original `ServeHTTP()` implementation used `req.BasicAuth()` for the authentication check.

Because routing and authentication use different credential sources, a request can be routed to a protected backend based on the `Proxy-Authorization` username while the authentication check is not performed against the same credentials. This creates an authentication bypass when `routeByHTTPUser`, `httpUser`, and `httpPassword` are used together.

This is not a universal anonymous bypass for all frp HTTP proxies; it is specific to deployments that use `routeByHTTPUser` and where the target user value is known or can be inferred.

A minimal fix is to make the authentication check in proxy mode use the same credential source as route selection, i.e. to derive proxy-mode credentials from `Proxy-Authorization` consistently.

From local Git history analysis, this logic appears to have been introduced by commit `4af85da0c2c6eb981142a8fdb44f885d26cb9d08`, with the earliest containing release tag appearing to be `v0.43.0`.

### PoC
I reproduced the issue with the official `frp_0.68.0_linux_amd64.tar.gz` release binaries both locally and on an internet-reachable test server under my control.

Minimal setup:
- `frps` exposes an HTTP vhost entrypoint.
- One HTTP proxy is configured with:
  - `customDomains = ["example.test"]`
  - `routeByHTTPUser = "alice"`
  - `httpUser = "alice"`
  - `http[CREDENTIAL_REDACTED]"`
- The protected backend returns a constant marker string: `PRIVATE`.

Minimal request flow:
1. Direct unauthenticated request:
   - `curl -i --proxy '' -H 'Host: example.test' http://<FRPS_HOST>:<VHOST_HTTP_PORT>/`
   - Result: `404 Not Found`

2. Direct request with correct backend credentials:
   - `curl -i --proxy '' -u alice:secret -H 'Host: example.test' http://<FRPS_HOST>:<VHOST_HTTP_PORT>/`
   - Result: `200 OK`, body contains `PRIVATE`

3. Proxy-style r