istio/istio · info

Only requests from localhost are allowed

Error message

Only requests from localhost are allowed

What it means

HTTP 403 'Only requests from localhost are allowed' returned by the pprof index handler (handlePprofIndex) of the pilot-agent status server (pilot/cmd/pilot-agent/status/server.go). The debug/pprof endpoints are deliberately restricted: istioNetUtil.IsRequestFromLocalhost checks the request's remote address, and anything not originating from the pod's loopback interface is rejected with 403 before pprof.Index runs. This is a security guard, not a malfunction.

Source

Thrown at pilot/cmd/pilot-agent/status/server.go:496

			case <-ctx.Done():
				// We are shutting down already, don't trigger SIGTERM
				return
			default:
				// If the server errors then pilot-agent can never pass readiness or liveness probes
				// Therefore, trigger graceful termination by sending SIGTERM to the binary pid
				notifyExit()
			}
		}
	}()

	// Wait for the agent to be shut down.
	<-ctx.Done()
	log.Info("Status server has successfully terminated")
}

func (s *Server) handlePprofIndex(w http.ResponseWriter, r *http.Request) {
	if !istioNetUtil.IsRequestFromLocalhost(r) {
		http.Error(w, "Only requests from localhost are allowed", http.StatusForbidden)
		return
	}

	pprof.Index(w, r)
}

func (s *Server) handlePprofCmdline(w http.ResponseWriter, r *http.Request) {
	if !istioNetUtil.IsRequestFromLocalhost(r) {
		http.Error(w, "Only requests from localhost are allowed", http.StatusForbidden)
		return
	}

	pprof.Cmdline(w, r)
}

func (s *Server) handlePprofSymbol(w http.ResponseWriter, r *http.Request) {
	if !istioNetUtil.IsRequestFromLocalhost(r) {
		http.Error(w, "Only requests from localhost are allowed", http.StatusForbidden)

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Exec into the pod and curl the endpoint locally: kubectl exec -n <ns> <pod> -c <container> -- curl -s localhost:15014/debug/pprof/heap > heap.prof
  2. Or run pprof from inside: kubectl exec ... -- go tool pprof http://localhost:15014/debug/pprof/profile (go tooling must exist in the image)
  3. Do not try to bypass via service/ingress - the restriction is intentional; expose metrics through the scraped /stats or /metrics routes instead
  4. For nodes, an alternative is a debug proxy that runs inside the pod's netns

Example fix

# before (403 - request arrives from non-loopback)
kubectl port-forward -n istio-system pod/istiod-xxx 15014:15014 &
curl http://<node-ip>:15014/debug/pprof/

# after
kubectl exec -n istio-system istiod-xxx -- curl -s -o /tmp/heap.prof http://localhost:15014/debug/pprof/heap
kubectl cp istio-system/istiod-xxx:/tmp/heap.prof ./heap.prof
go tool pprof -top ./heap.prof
Defensive patterns

Strategy: validation

Validate before calling

// Only issue the request when it will originate from the pod's loopback:
// (caller-side precondition, e.g. inside kubectl exec / in-pod sidecar)
if remoteAddrIsNotLoopback {
    // don't call /debug/pprof/*; route through exec-in-pod instead
}

Try / catch

resp, err := http.Get(pprofURL)
if err == nil && resp.StatusCode == http.StatusForbidden {
    // expected for remote callers: switch to kubectl exec-based localhost access
}

Prevention

When it happens

Trigger: Sending a request to /debug/pprof/ on the agent's status port from outside the pod: via a NodePort/LoadBalancer/service VIP, an ingress, a scrape from another pod, or some port-forward paths where the connection terminates from a non-loopback address.

Common situations: Trying to attach go tool pprof or curl to the agent's debug endpoints through the service IP; profiling setups copied from services that expose pprof publicly; expecting kubectl port-forward to appear as localhost (traffic is proxied via the API server and can arrive with a non-loopback source).

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/ffaa14fd2695ebb7. Report an issue: GitHub.