Overview
Verified by Nguyen Huy Hoang (hoanggxyuuki) & Tong Hoang Gia (uziii2208). The default deployment of the Knowns browser server operates in a fully unauthenticated state, binds to all network interfaces (0.0.0.0), and exposes the entire management API to the local network. Furthermore, the server includes a built-in Cloudflare Quick Tunnel feature that can be triggered via an unauthenticated API endpoint (POST /api/tunnel/start) or a CLI flag, instantly exposing the unauthenticated instance to the public internet.
This insecure default posture acts as the linchpin for the entire application's threat model, escalating every subsequent vulnerability (Path Traversal, SSRF, XSS, and the previously identified RCE chain) from localized/network-restricted issues to zero-credential remote attacks from the public internet. When exposed via the tunnel feature, the attack surface yields a Critical severity (CVSS 3.1: 9.8).
Root Cause
Insecure Default Authentication
In internal/server/auth.go, the authentication middleware explicitly bypasses all security checks if the server is started without a password:
if am == nil || !am.HasPassword() {
next.ServeHTTP(w, r)
return
}
Because there is no mandatory first-time setup or auto-generated token, a default installation has no password. Consequently, every API endpoint-including configuration, workspace management, LSP control, and tunneling-is fully accessible to anyone with network reach.
Insecure Default Network Binding
During server initialization, the listener is typically configured using a pattern like net.Listen("tcp", ":"+port). In Go, omitting the host portion of the address implicitly binds the server to all available network interfaces (0.0.0.0). This exposes the unauthenticated API to any device on the local network, rather than restricting it to 127.0.0.1 (localhost).
Unauthenticated Public Exposure (Cloudflare Tunnel)
The application includes a feature to create a Cloudflare Quick Tunnel for remote access. In internal/server/routes/tunnel.go, the SetupTunnelRoutes function registers the /start endpoint which directly calls tunnelMgr.Start(). There are absolutely no internal authorization checks within the handler; it delegates security entirely to the global middleware.
Because the global AuthManager.Middleware is a no-op by default, any unauthenticated user on the LAN can send a single request to POST /api/tunnel/start. This immediately provisions a public internet URL pointing directly to the unauthenticated management API, bypassing any local firewall or NAT protections.
Attack Vector
| Phase | Request / Action | Effect |
|---|---|---|
| 1. Reconnaissance | GET /api/auth/status |
Confirms {"authenticated": false, "protected": false}, verifying the server is unauthenticated. |
| 2. Exposure | POST /api/tunnel/start |
Triggers tunnelMgr.Start() via the unauthenticated API, generating a public .trycloudflare.com URL accessible from the internet. |
| 3. Exploitation | Chain with secondary vulnerabilities | Attacker uses the newly exposed public URL to execute write primitives (e.g., POST /api/docs), trigger SSRF, or execute the LSP RCE chain from anywhere on the internet. |
Preconditions: Knowns running with default config (no --password flag); server started without explicitly binding to 127.0.0.1.
Analysis
Auth Bypass - auth.go
The middleware design relies on an opt-in security model rather than a fail-closed model. The check !am.HasPassword() assumes that an empty password implies a local, trusted development environment. However, because the server binds to 0.0.0.0 by default, this assumption is fundamentally broken in any real-world deployment. There is no mechanism to enforce password creation before the server begins accepting connections.
Network Binding - Server Initialization
The use of net.Listen("tcp", ":"+port) is a common anti-pattern for local development tools that are inadvertently deployed to production or shared networks. Without explicitly defaulting to "127.0.0.1:" + port, the Go standard library binds to the wildcard address, making the service discoverable and reachable via ARP/routing on the local subnet.
Tunnel Endpoint - tunnel.go
The SetupTunnelRoutes function registers the tunnel control endpoints directly onto the router. Inside the /start handler, the code unconditionally executes:
// internal/server/routes/tunnel.go (vulnerable sink)
r.Post("/start", func(w http.ResponseWriter, r *http.Request) {
url, err := tunnelMgr.Start() // No internal auth check
// ...
})
It delegates security entirely to the global middleware. Since the global middleware is bypassed when no password is set, the tunnel creation becomes a zero-credential action. Cloudflare Quick Tunnels (cloudflared tunnel --url) punch through NAT/firewalls, effectively turning a LAN-restricted service into a public-facing target. This is a classic Missing Function Level Access Control (CWE-862) flaw compounded by the insecure global state.
Proof of Concept (PoC)
./bin/knowns browser --port 6420 --no-open # no --password
curl -s http://127.0.0.1:6420/api/auth/status # {"authenticated":false,"protected":false}
curl -s -X POST http://127.0.0.1:6420/api/docs -H 'Content-Type: application/json' \
-d '{"path":"pwn","content":"# owned"}' # 200 — write without auth
Impact
Every other finding in this audit (traversal, SSRF, XSS, RCE chain) goes from "requires access" to "zero-credential from LAN/internet" — this is the linchpin that makes overall risk = CRITICAL.
Remediation
- Fail closed: require a password/token (auto-generate and print it), refuse to start without auth on non-loopback binds
- Default bind
127.0.0.1unless--host - Tunnel opt-in with clear warning