Skip to content

Commit 0b73e61

Browse files
Merge commit from fork
Add test
1 parent 58da65f commit 0b73e61

4 files changed

Lines changed: 39 additions & 8 deletions

File tree

dgraph/cmd/alpha/http_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,26 @@ func TestHealth(t *testing.T) {
827827
require.True(t, info[0].Uptime > int64(time.Duration(1)))
828828
}
829829

830+
// TestPprofCmdlineNotExposed ensures that /debug/pprof/cmdline is not reachable
831+
// without authentication. The endpoint exposes the full process command line,
832+
// which may include the admin token passed via --security "token=...".
833+
// The other pprof sub-endpoints should remain accessible.
834+
func TestPprofCmdlineNotExposed(t *testing.T) {
835+
// cmdline must be blocked — it leaks the admin token from process args.
836+
resp, err := http.Get(fmt.Sprintf("%s/debug/pprof/cmdline", addr))
837+
require.NoError(t, err)
838+
defer resp.Body.Close()
839+
require.Equal(t, http.StatusNotFound, resp.StatusCode,
840+
"/debug/pprof/cmdline should return 404; got %d", resp.StatusCode)
841+
842+
// Sanity-check that other pprof endpoints are still reachable.
843+
resp2, err := http.Get(fmt.Sprintf("%s/debug/pprof/heap", addr))
844+
require.NoError(t, err)
845+
defer resp2.Body.Close()
846+
require.Equal(t, http.StatusOK, resp2.StatusCode,
847+
"/debug/pprof/heap should return 200; got %d", resp2.StatusCode)
848+
}
849+
830850
func setDrainingMode(t *testing.T, enable bool, accessJwt string) {
831851
drainingRequest := `mutation drain($enable: Boolean) {
832852
draining(enable: $enable) {

dgraph/cmd/alpha/run.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,17 @@ func setupServer(closer *z.Closer, enableMcp bool) {
620620
}
621621
}
622622

623-
go x.StartListenHttpAndHttps(httpListener, tlsCfg, x.ServerCloser)
623+
// Block /debug/pprof/cmdline — importing net/http/pprof registers it on
624+
// http.DefaultServeMux, but it exposes the full process command line which
625+
// may include the admin token from --security "token=...".
626+
serverHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
627+
if r.URL.Path == "/debug/pprof/cmdline" {
628+
http.NotFound(w, r)
629+
return
630+
}
631+
http.DefaultServeMux.ServeHTTP(w, r)
632+
})
633+
go x.StartListenHttpAndHttps(httpListener, tlsCfg, x.ServerCloser, serverHandler)
624634

625635
go func() {
626636
defer x.ServerCloser.Done()

dgraph/cmd/zero/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ func run() {
287287

288288
tlsCfg, err := x.LoadServerTLSConfig(Zero.Conf)
289289
x.Check(err)
290-
go x.StartListenHttpAndHttps(httpListener, tlsCfg, st.zero.closer)
290+
go x.StartListenHttpAndHttps(httpListener, tlsCfg, st.zero.closer, nil)
291291

292292
baseMux := http.NewServeMux()
293293
http.Handle("/", audit.AuditRequestHttp(baseMux))

x/server.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ var (
2727
ServerCloser = z.NewCloser(0)
2828
)
2929

30-
func StartListenHttpAndHttps(l net.Listener, tlsCfg *tls.Config, closer *z.Closer) {
30+
func StartListenHttpAndHttps(l net.Listener, tlsCfg *tls.Config, closer *z.Closer, h http.Handler) {
3131
defer closer.Done()
3232
m := cmux.New(l)
33-
startServers(m, tlsCfg)
33+
startServers(m, tlsCfg, h)
3434
err := m.Serve()
3535
if err != nil {
3636
glog.Errorf("error from cmux serve: %v", err)
3737
}
3838
}
3939

40-
func startServers(m cmux.CMux, tlsConf *tls.Config) {
40+
func startServers(m cmux.CMux, tlsConf *tls.Config, h http.Handler) {
4141
httpRule := m.Match(func(r io.Reader) bool {
4242
// no tls config is provided. http is being used.
4343
if tlsConf == nil {
@@ -53,19 +53,20 @@ func startServers(m cmux.CMux, tlsConf *tls.Config) {
5353
// monitoring tools which operate without authentication.
5454
return strings.HasPrefix(path, "/health")
5555
})
56-
go startListen(httpRule)
56+
go startListen(httpRule, h)
5757

5858
// if tls is enabled, make tls encryption based connections as default
5959
if tlsConf != nil {
6060
httpsRule := m.Match(cmux.Any())
6161
// this is chained listener. tls listener will decrypt
6262
// the message and send it in plain text to HTTP server
63-
go startListen(tls.NewListener(httpsRule, tlsConf))
63+
go startListen(tls.NewListener(httpsRule, tlsConf), h)
6464
}
6565
}
6666

67-
func startListen(l net.Listener) {
67+
func startListen(l net.Listener, h http.Handler) {
6868
srv := &http.Server{
69+
Handler: h, // nil falls back to http.DefaultServeMux
6970
ReadTimeout: 10 * time.Second,
7071
WriteTimeout: 600 * time.Second,
7172
IdleTimeout: 2 * time.Minute,

0 commit comments

Comments
 (0)