CORS wildcard applies to the authenticated /metrics route, and advertises methods that do not exist #100
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The CORS middleware is registered globally and is both too broad in scope and inaccurate about what the service supports.
Current state (audited against
origin/main, commit9347a28)internal/middleware/middleware.go:173-187:Registered globally at
internal/server/routes.go:25(s.router.Use(s.mw.CORS())).Two distinct problems:
1. Wildcard CORS is applied to the authenticated route.
REPO_POLICIES.mdsays wildcardAccess-Control-Allow-Origin"is acceptable only for public, unauthenticated read-only APIs", and that "authenticated endpoints must restrictAccess-Control-Allow-Originto an explicit allowlist of known origins."/metricsis Basic-Auth protected (internal/server/routes.go:54-63,MetricsAuth()atinternal/middleware/middleware.go:189-205) yet inherits the global wildcard, andAllowedHeadersexplicitly includesAuthorization. Wildcard CORS is genuinely fine for/,/api/v1/status, and the healthchecks — those are exactly the "public, unauthenticated, read-only" case the policy carves out. It is not fine for/metrics.2. The advertised method set is fiction. Every route in
internal/server/routes.gois registered withGet(). There is not a singlePOST,PUT, orDELETEhandler anywhere in the service, and no handler reads a request body at all (grep for.Body,NewDecoder,ReadAll,MaxBytesReaderacrossinternal/handlers,internal/server,internal/middlewarereturns nothing). AdvertisingPOST, PUT, DELETE— andX-CSRF-Token, when there are no forms and no state-mutating endpoints — is over-broad configuration that misrepresents the service's surface.Definition of done
AllowedMethodsis reduced to the methods the service actually serves:GETandOPTIONS.X-CSRF-Tokenis removed fromAllowedHeaders(no forms, no state-mutating endpoints exist). Keep only headers a cross-origin reader genuinely needs./metrics. Either scope the CORS middleware to the public route group only and leave/metricswithout CORS entirely (preferred — a Prometheus scraper is not a browser and needs no CORS), or give the/metricsgroup its own restrictive CORS configuration. Whichever is chosen, the public routes (/,/s/...,/api/v1/status,/health,/.well-known/healthcheck) keep their wildcard, which the policy permits.internal/middlewareorinternal/serverassert: a cross-originGETagainst a public route still getsAccess-Control-Allow-Origin: *; a request against/metricsdoes not get a wildcardAccess-Control-Allow-Origin; and the advertisedAccess-Control-Allow-Methodsno longer containsPOST,PUT, orDELETE.make checkis green, andTODO.mdis updated in the same commit as the work.The finishing commit's title must end with
(closes #N)referencing this issue.Out of scope
Security response headers (#98),
http.Servertimeouts (#99), and rate limiting are tracked separately — do not fold them into this PR.