{"record":{"id":"ffaa14fd2695ebb7","repo":"istio/istio","slug":"only-requests-from-localhost-are-allowed","errorCode":null,"errorMessage":"Only requests from localhost are allowed","messagePattern":"Only requests from localhost are allowed","errorType":"http","errorClass":null,"httpStatus":403,"severity":"info","filePath":"pilot/cmd/pilot-agent/status/server.go","lineNumber":496,"sourceCode":"\t\t\tcase <-ctx.Done():\n\t\t\t\t// We are shutting down already, don't trigger SIGTERM\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t\t// If the server errors then pilot-agent can never pass readiness or liveness probes\n\t\t\t\t// Therefore, trigger graceful termination by sending SIGTERM to the binary pid\n\t\t\t\tnotifyExit()\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Wait for the agent to be shut down.\n\t<-ctx.Done()\n\tlog.Info(\"Status server has successfully terminated\")\n}\n\nfunc (s *Server) handlePprofIndex(w http.ResponseWriter, r *http.Request) {\n\tif !istioNetUtil.IsRequestFromLocalhost(r) {\n\t\thttp.Error(w, \"Only requests from localhost are allowed\", http.StatusForbidden)\n\t\treturn\n\t}\n\n\tpprof.Index(w, r)\n}\n\nfunc (s *Server) handlePprofCmdline(w http.ResponseWriter, r *http.Request) {\n\tif !istioNetUtil.IsRequestFromLocalhost(r) {\n\t\thttp.Error(w, \"Only requests from localhost are allowed\", http.StatusForbidden)\n\t\treturn\n\t}\n\n\tpprof.Cmdline(w, r)\n}\n\nfunc (s *Server) handlePprofSymbol(w http.ResponseWriter, r *http.Request) {\n\tif !istioNetUtil.IsRequestFromLocalhost(r) {\n\t\thttp.Error(w, \"Only requests from localhost are allowed\", http.StatusForbidden)","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/istio/istio/blob/8dc789c5cf17517c64e3c36cb3288230f149dfae/pilot/cmd/pilot-agent/status/server.go#L478-L514","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["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","Or run pprof from inside: kubectl exec ... -- go tool pprof http://localhost:15014/debug/pprof/profile (go tooling must exist in the image)","Do not try to bypass via service/ingress - the restriction is intentional; expose metrics through the scraped /stats or /metrics routes instead","For nodes, an alternative is a debug proxy that runs inside the pod's netns"],"exampleFix":"# before (403 - request arrives from non-loopback)\nkubectl port-forward -n istio-system pod/istiod-xxx 15014:15014 &\ncurl http://<node-ip>:15014/debug/pprof/\n\n# after\nkubectl exec -n istio-system istiod-xxx -- curl -s -o /tmp/heap.prof http://localhost:15014/debug/pprof/heap\nkubectl cp istio-system/istiod-xxx:/tmp/heap.prof ./heap.prof\ngo tool pprof -top ./heap.prof","handlingStrategy":"validation","validationCode":"// Only issue the request when it will originate from the pod's loopback:\n// (caller-side precondition, e.g. inside kubectl exec / in-pod sidecar)\nif remoteAddrIsNotLoopback {\n    // don't call /debug/pprof/*; route through exec-in-pod instead\n}","typeGuard":null,"tryCatchPattern":"resp, err := http.Get(pprofURL)\nif err == nil && resp.StatusCode == http.StatusForbidden {\n    // expected for remote callers: switch to kubectl exec-based localhost access\n}","preventionTips":["Standardize on kubectl exec ... -- curl localhost:<status-port>/debug/pprof/ for profiles","Do not expose the agent status port through Services/ingress","Treat 403 here as the guard working as designed, not an outage"],"tags":["pprof","debugging","security","http","istio"],"backgroundTag":null,"analyzedSha":"8dc789c5cf17517c64e3c36cb3288230f149dfae","analyzedAt":"2026-08-15T15:16:55.434Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}