Fix SEC-07: disable static file directory listing

- Add noDirListing handler wrapper that returns 404 for directory
  requests (paths ending with "/" or empty path) instead of delegating
  to http.FileServerFS which would render an index page
- Wrap the static file server in Register() with noDirListing
- Add tests verifying GET /static/ returns 404 and GET /static/style.css
  still returns 200

Security: directory listings exposed the names of all static assets,
leaking framework details. The wrapper blocks directory index responses
while preserving normal file serving.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 00:41:46 -07:00
parent 586d4e3355
commit 036a0b8be4
2 changed files with 48 additions and 1 deletions

View File

@@ -355,6 +355,34 @@ func authenticatedGET(t *testing.T, sessionToken string, path string) *http.Requ
return req
}
// TestStaticDirectoryListingDisabled verifies that GET /static/ returns 404
// instead of a directory listing (SEC-07).
func TestStaticDirectoryListingDisabled(t *testing.T) {
mux := newTestMux(t)
req := httptest.NewRequest(http.MethodGet, "/static/", nil)
rr := httptest.NewRecorder()
mux.ServeHTTP(rr, req)
if rr.Code != http.StatusNotFound {
t.Errorf("GET /static/ status = %d, want %d (directory listing must be disabled)", rr.Code, http.StatusNotFound)
}
}
// TestStaticFileStillServed verifies that individual static files are still
// served normally after the directory listing fix (SEC-07).
func TestStaticFileStillServed(t *testing.T) {
mux := newTestMux(t)
req := httptest.NewRequest(http.MethodGet, "/static/style.css", nil)
rr := httptest.NewRecorder()
mux.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Errorf("GET /static/style.css status = %d, want %d", rr.Code, http.StatusOK)
}
}
// TestSetPGCredsRejectsHumanAccount verifies that the PUT /accounts/{id}/pgcreds
// endpoint returns 400 when the target account is a human (not system) account.
func TestSetPGCredsRejectsHumanAccount(t *testing.T) {