test: security regression — IDOR payment-check scoping, CORS preflight 403, rate limiter pruning, services error leakage
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+65
-2
@@ -177,8 +177,8 @@ func TestCORSPreflight_RejectsUnlistedOrigin(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusNoContent {
|
||||
t.Errorf("expected preflight 204, got %d", rr.Code)
|
||||
if rr.Code != http.StatusForbidden {
|
||||
t.Errorf("expected preflight 403 for unlisted origin, got %d", rr.Code)
|
||||
}
|
||||
if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "" {
|
||||
t.Errorf("expected no Access-Control-Allow-Origin on preflight for unlisted origin, got %q", got)
|
||||
@@ -290,3 +290,66 @@ func TestIsWeakJWTSecret_EntropyGate(t *testing.T) {
|
||||
t.Errorf("expected high-entropy secret %q to be accepted", weak[len(weak)-1])
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// CORS fix: OPTIONS from non-allowed origins returns 403
|
||||
// ============================================================
|
||||
|
||||
// TestCORSPreflight_NonAllowedOrigin_Returns403 verifies the CORS fix: an
|
||||
// OPTIONS preflight from a non-allowed origin must return 403 Forbidden
|
||||
// (not 204 No Content) and must NOT include the Access-Control-Allow-Origin
|
||||
// header, so a browser cannot be tricked into believing CORS is granted.
|
||||
func TestCORSPreflight_NonAllowedOrigin_Returns403(t *testing.T) {
|
||||
t.Setenv("FRONTEND_ORIGIN", "https://app.example.com")
|
||||
handler := corsMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodOptions, "/api/bookings", nil)
|
||||
req.Header.Set("Origin", "https://evil.com")
|
||||
req.Header.Set("Access-Control-Request-Method", "POST")
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusForbidden {
|
||||
t.Errorf("expected 403 Forbidden for non-allowed origin OPTIONS, got %d", rr.Code)
|
||||
}
|
||||
if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "" {
|
||||
t.Errorf("expected no Access-Control-Allow-Origin header for non-allowed origin, got %q", got)
|
||||
}
|
||||
// Also verify no CORS headers are leaked.
|
||||
if got := rr.Header().Get("Access-Control-Allow-Methods"); got != "" {
|
||||
t.Errorf("expected no Access-Control-Allow-Methods header for non-allowed origin, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCORSPreflight_AllowedOrigin_Returns204 verifies that an OPTIONS preflight
|
||||
// from a configured origin returns 204 No Content with proper CORS headers.
|
||||
func TestCORSPreflight_AllowedOrigin_Returns204(t *testing.T) {
|
||||
t.Setenv("FRONTEND_ORIGIN", "https://app.example.com")
|
||||
handler := corsMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodOptions, "/api/bookings", nil)
|
||||
req.Header.Set("Origin", "https://app.example.com")
|
||||
req.Header.Set("Access-Control-Request-Method", "POST")
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusNoContent {
|
||||
t.Errorf("expected 204 No Content for allowed origin OPTIONS, got %d", rr.Code)
|
||||
}
|
||||
if got := rr.Header().Get("Access-Control-Allow-Origin"); got != "https://app.example.com" {
|
||||
t.Errorf("expected Access-Control-Allow-Origin %q, got %q", "https://app.example.com", got)
|
||||
}
|
||||
if got := rr.Header().Get("Vary"); got != "Origin" {
|
||||
t.Errorf("expected Vary: Origin header, got %q", got)
|
||||
}
|
||||
if got := rr.Header().Get("Access-Control-Allow-Methods"); got == "" {
|
||||
t.Errorf("expected Access-Control-Allow-Methods header to be set")
|
||||
}
|
||||
if got := rr.Header().Get("Access-Control-Allow-Headers"); got == "" {
|
||||
t.Errorf("expected Access-Control-Allow-Headers header to be set")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user