Skip to content

Commit 3ccffb8

Browse files
committed
Don't expose debug vars by default (fix: #799)
Signed-off-by: Maksym Pavlenko <[email protected]>
1 parent ce2b233 commit 3ccffb8

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

config.toml.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ path = "test"
2121
web_ui = true
2222
# Optional. If you want to use TLS you must set the TLS flag and path to the certificate file and private key file.
2323
tls = true
24-
certificate_path = "/var/www/cert.pem"
24+
certificate_path = "/var/www/cert.pem"
2525
key_file_path = "/var/www/priv.pem"
26+
# Optional. Enable debug endpoints (/debug/vars) for runtime metrics. Disabled by default for security.
27+
# Only enable this if you need to debug the application and the endpoint is not publicly accessible.
28+
debug_endpoints = false
2629

2730
# Configure where to store the episode data
2831
[storage]

services/web/server.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package web
22

33
import (
44
"encoding/json"
5+
"expvar"
56
"fmt"
67
"net/http"
78
"time"
@@ -39,6 +40,8 @@ type Config struct {
3940
DataDir string `toml:"data_dir"`
4041
// WebUIEnabled is a flag indicating if web UI is enabled
4142
WebUIEnabled bool `toml:"web_ui"`
43+
// DebugEndpoints enables /debug/vars endpoint for runtime metrics (disabled by default)
44+
DebugEndpoints bool `toml:"debug_endpoints"`
4245
}
4346

4447
func New(cfg Config, storage http.FileSystem, database db.Storage) *Server {
@@ -59,13 +62,25 @@ func New(cfg Config, storage http.FileSystem, database db.Storage) *Server {
5962
srv.Addr = fmt.Sprintf("%s:%d", bindAddress, port)
6063
log.Debugf("using address: %s:%s", bindAddress, srv.Addr)
6164

65+
// Use a custom mux instead of http.DefaultServeMux to avoid exposing
66+
// debug endpoints registered by imported packages (security fix for #799)
67+
mux := http.NewServeMux()
68+
6269
fileServer := http.FileServer(storage)
6370

6471
log.Debugf("handle path: /%s", cfg.Path)
65-
http.Handle(fmt.Sprintf("/%s", cfg.Path), fileServer)
72+
mux.Handle(fmt.Sprintf("/%s", cfg.Path), fileServer)
6673

6774
// Add health check endpoint
68-
http.HandleFunc("/health", srv.healthCheckHandler)
75+
mux.HandleFunc("/health", srv.healthCheckHandler)
76+
77+
// Optionally enable debug endpoints (disabled by default for security)
78+
if cfg.DebugEndpoints {
79+
log.Info("debug endpoints enabled at /debug/vars")
80+
mux.Handle("/debug/vars", expvar.Handler())
81+
}
82+
83+
srv.Handler = mux
6984

7085
return &srv
7186
}

services/web/server_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package web
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"strings"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
type mockFileSystem struct{}
13+
14+
func (m *mockFileSystem) Open(name string) (http.File, error) {
15+
return nil, http.ErrMissingFile
16+
}
17+
18+
func TestDebugEndpointDisabledByDefault(t *testing.T) {
19+
cfg := Config{
20+
Port: 8080,
21+
Path: "feeds",
22+
}
23+
24+
srv := New(cfg, &mockFileSystem{}, nil)
25+
26+
req := httptest.NewRequest(http.MethodGet, "/debug/vars", nil)
27+
rec := httptest.NewRecorder()
28+
29+
srv.Handler.ServeHTTP(rec, req)
30+
31+
// Should return 404 when debug endpoints are disabled
32+
assert.Equal(t, http.StatusNotFound, rec.Code)
33+
// Should NOT contain expvar data
34+
assert.False(t, strings.Contains(rec.Body.String(), "cmdline"))
35+
}
36+
37+
func TestDebugEndpointEnabledWhenConfigured(t *testing.T) {
38+
cfg := Config{
39+
Port: 8080,
40+
Path: "feeds",
41+
DebugEndpoints: true,
42+
}
43+
44+
srv := New(cfg, &mockFileSystem{}, nil)
45+
46+
req := httptest.NewRequest(http.MethodGet, "/debug/vars", nil)
47+
rec := httptest.NewRecorder()
48+
49+
srv.Handler.ServeHTTP(rec, req)
50+
51+
// Should return 200 and JSON content when debug endpoints are enabled
52+
assert.Equal(t, http.StatusOK, rec.Code)
53+
assert.Contains(t, rec.Header().Get("Content-Type"), "application/json")
54+
// Verify it contains expvar data (cmdline is always present)
55+
assert.True(t, strings.Contains(rec.Body.String(), "cmdline"))
56+
}

0 commit comments

Comments
 (0)