From 0867490ae091c7d570e606911f14a1aa46ff011e Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 4 Feb 2026 16:17:00 +0000 Subject: [PATCH] Block proxy non-admin password changes --- internal/api/security_regression_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/api/security_regression_test.go b/internal/api/security_regression_test.go index a60c28134..8c221d79d 100644 --- a/internal/api/security_regression_test.go +++ b/internal/api/security_regression_test.go @@ -323,6 +323,26 @@ func TestChangePasswordRequiresAuthInAPIMode(t *testing.T) { } } +func TestChangePasswordRejectsProxyNonAdmin(t *testing.T) { + cfg := newTestConfigWithTokens(t) + cfg.ProxyAuthSecret = "proxy-secret" + cfg.ProxyAuthUserHeader = "X-Remote-User" + cfg.ProxyAuthRoleHeader = "X-Remote-Roles" + cfg.ProxyAuthAdminRole = "admin" + + router := NewRouter(cfg, nil, nil, nil, nil, "1.0.0") + + req := httptest.NewRequest(http.MethodPost, "/api/security/change-password", strings.NewReader(`{}`)) + req.Header.Set("X-Proxy-Secret", cfg.ProxyAuthSecret) + req.Header.Set("X-Remote-User", "viewer-user") + req.Header.Set("X-Remote-Roles", "viewer") + rec := httptest.NewRecorder() + router.Handler().ServeHTTP(rec, req) + if rec.Code != http.StatusForbidden { + t.Fatalf("expected 403 for non-admin proxy password change, got %d", rec.Code) + } +} + func TestResetLockoutRequiresAuthInAPIMode(t *testing.T) { record := newTokenRecord(t, "reset-lockout-token-123.12345678", []string{config.ScopeSettingsWrite}, nil) cfg := newTestConfigWithTokens(t, record)