cloudflare/cloudflared · info
forbidden
Error message
forbidden
What it means
The metrics server's router explicitly blocks /debug/pprof/cmdline and responds 'forbidden' with HTTP 403. This is intentional security behavior: the cmdline pprof endpoint would expose the full command line (os.Args), which can contain secret tunnel tokens or credentials. Hitting this error means you requested a deliberately disabled debug endpoint.
Source
Thrown at metrics/metrics.go:76
QuickTunnelHostname string
Orchestrator orchestrator
ShutdownTimeout time.Duration
}
type orchestrator interface {
GetVersionedConfigJSON() ([]byte, error)
}
func newMetricsHandler(
config Config,
log *zerolog.Logger,
) *http.ServeMux {
router := http.NewServeMux()
// Block /debug/pprof/cmdline to prevent leaking secret command-line arguments
// (e.g. tunnel tokens) that are exposed via os.Args.
router.HandleFunc("/debug/pprof/cmdline", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "forbidden", http.StatusForbidden)
})
router.Handle("/debug/", http.DefaultServeMux)
router.Handle("/metrics", promhttp.Handler())
router.HandleFunc("/healthcheck", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, "OK\n")
})
if config.ReadyServer != nil {
router.Handle("/ready", config.ReadyServer)
}
router.HandleFunc("/quicktunnel", func(w http.ResponseWriter, r *http.Request) {
_, _ = fmt.Fprintf(w, `{"hostname":"%s"}`, config.QuickTunnelHostname)
})
if config.Orchestrator != nil {
router.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) {
json, err := config.Orchestrator.GetVersionedConfigJSON()
if err != nil {
w.WriteHeader(500)
_, _ = fmt.Fprintf(w, "ERR: %v", err)View on GitHub (pinned to 2253eeeb25)
Solutions
- Do not rely on /debug/pprof/cmdline; use the process command line via ps/proc instead: ps -o args= -p $(pidof cloudflared)
- Profile via the other pprof endpoints (/debug/pprof/profile, /debug/pprof/heap) which remain served under /debug/
- If you need the flags, inspect your own deployment configuration or systemd unit rather than the endpoint
- This is by design to prevent token leakage — do not attempt to bypass it; rotate any tokens you consider exposed
Example fix
// before: fetching command line via blocked endpoint curl http://localhost:20241/debug/pprof/cmdline // after: read it from the process instead ps -o args= -p "$(pidof cloudflared)"
Defensive patterns
Strategy: fallback
Validate before calling
if strings.HasSuffix(pprofPath, "/debug/pprof/cmdline") {
// skip: intentionally blocked by cloudflared metrics router (403)
} Try / catch
resp, err := http.Get(metricsURL + "/debug/pprof/profile?seconds=10")
if err == nil && resp.StatusCode == http.StatusForbidden {
// cmdline/profile blocked: gather diagnostics from OS tooling instead
} Prevention
- Never scrape /debug/pprof/cmdline on cloudflared; it is deliberately forbidden
- Use ps/proc filesystem for command-line inspection
- Restrict metrics endpoint access to trusted interfaces anyway
- Rotate tokens if any secret was exposed through other debug channels
When it happens
Trigger: An HTTP GET/POST to http://<metrics-host>:<metrics-port>/debug/pprof/cmdline on the cloudflared metrics listener returns 403 with body 'forbidden'.
Common situations: Developer profiling cloudflared with standard pprof tooling expects cmdline to work; security scanners flagging the endpoint; automation scraping all pprof endpoints; users unfamiliar with why this one endpoint is blocked while /debug/ itself is served.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- --metrics has to be provided
- ErrMetricsServerNotFound
- ErrMultipleMetricsServerFound
- failed to listen to default metrics address: %w
- failed to bind to address (%s): %w
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/9866209e48073242.
Report an issue: GitHub.