mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 14:51:30 +00:00
fix(api/cors): narrow Bundle-2 routes from wildcard to NewCORS(corsCfg)
Closes CRIT-3 of the 2026-05-10 audit. Bundle 2's OIDC handshake +
back-channel-logout + logout + bootstrap + breakglass-login routes were
wrapped by middleware.CORS — a hard-coded
Access-Control-Allow-Origin: * middleware that ignored the operator's
CERTCTL_CORS_ORIGINS knob (CWE-942). The properly-configured
middleware.NewCORS(corsCfg) exists right next to it but wasn't used here.
The deprecation comment on middleware.CORS said "Kept for health endpoints"
but Bundle 2 added four additional call sites without converting them.
This commit:
- Renames middleware.CORS -> middleware.CORSWildcard with a stronger doc
block making the security tradeoff explicit at every remaining call
site. The doc references the CI guard + the 2026-05-10 audit closure.
- Adds a CorsCfg middleware.CORSConfig field to router.HandlerRegistry
and threads it from cmd/server/main.go using the existing
cfg.CORS.AllowedOrigins value. The same config that drives the global
corsMiddleware now also drives the per-route NewCORS wraps for the
auth-exempt direct r.mux.Handle blocks.
- Swaps middleware.CORS -> middleware.NewCORS(reg.CorsCfg) for the 7
credentialed auth-exempt routes:
- GET /auth/oidc/login
- GET /auth/oidc/callback
- POST /auth/oidc/back-channel-logout
- POST /auth/logout
- POST /auth/breakglass/login
- GET /api/v1/auth/bootstrap
- POST /api/v1/auth/bootstrap
- Keeps middleware.CORSWildcard for the 4 credential-free probe routes:
- GET /health
- GET /ready
- GET /api/v1/version
- GET /api/v1/auth/info
- Adds scripts/ci-guards/cors-wildcard-allowlist.sh — pins the 4-route
allowlist; fails CI when a new middleware.CORSWildcard wrap appears
outside the allowlist. Adding a new wildcard call site requires
updating the allowlist AND documenting why in the commit body.
Operators who configured CERTCTL_CORS_ORIGINS=https://admin.example.com
expecting the OIDC + BCL + breakglass-login routes to honor it now do.
Previously those routes ignored the knob and emitted ACAO: * regardless.
Verification gate green:
- gofmt -l . clean
- go vet ./... clean
- go test -short -count=1 ./internal/api/... ./internal/auth/...
./internal/domain/auth/ ./internal/service/auth/ ./cmd/server/ pass
- go build ./... clean
- scripts/ci-guards/cors-wildcard-allowlist.sh passes (4 allowlisted
routes; zero violations)
CRIT-1 + CRIT-2 from the same audit are already closed on this branch
(commits 68ca42f, ca1e135); CRIT-4 / CRIT-5 remain open and continue
to block the v2.1.0 tag. Spec:
cowork/auth-bundles-fixes-2026-05-10/03-crit-3-cors-narrow.md.
Refs: cowork/auth-bundles-audit-2026-05-10.md CRIT-3
This commit is contained in:
@@ -371,9 +371,25 @@ func ContentType(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// CORS middleware adds CORS headers to allow cross-origin requests.
|
||||
// Deprecated: Use NewCORS for configurable origins. Kept for health endpoints.
|
||||
func CORS(next http.Handler) http.Handler {
|
||||
// CORSWildcard emits Access-Control-Allow-Origin: * unconditionally. ONLY use
|
||||
// for endpoints that (a) carry no credentials and (b) must be reachable from
|
||||
// any origin (e.g. K8s/Docker health probes, Prometheus scrapers, the GUI's
|
||||
// pre-login auth-info probe). Every call site MUST appear in
|
||||
// scripts/ci-guards/cors-wildcard-allowlist.sh — adding a new call site
|
||||
// without listing it in the allowlist fails CI.
|
||||
//
|
||||
// For credentialed endpoints (sessions, OIDC handshake, BCL, bootstrap,
|
||||
// breakglass-login, every /api/v1/* mutation route) use
|
||||
// middleware.NewCORS(corsCfg) which honors CERTCTL_CORS_ORIGINS and emits
|
||||
// per-origin headers (with Vary: Origin for cache correctness).
|
||||
//
|
||||
// History: this function was named `CORS` pre-2026-05-10 and was applied as
|
||||
// the default CORS middleware on the OIDC handshake, BCL, logout, bootstrap,
|
||||
// and breakglass-login routes — CRIT-3 of the 2026-05-10 audit
|
||||
// (cowork/auth-bundles-audit-2026-05-10.md). The fix narrowed those call
|
||||
// sites to NewCORS(corsCfg) and renamed the wildcard form to make the
|
||||
// security tradeoff explicit at every remaining call site.
|
||||
func CORSWildcard(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
|
||||
|
||||
Reference in New Issue
Block a user