CVE-2022-2583: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') (CWE-362)
value: A race condition can cause incorrect HTTP request routing.
CWE description: The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.
CVSS v3 base score: 3.7
Published: 2022-12-27T22:15Z
Repository: https://github.com/ntbosscher/gobase
Language: Go
Files changed: auth/httpauth/main.go
Commit date: 2020-11-05 16:49:43 -0500
Commit message: fix race condition in httpauth where the incorrect handler could be called for some calls

Diff: diff --git a/auth/httpauth/main.go b/auth/httpauth/main.go
index 5f19a70..8e0d272 100644
--- a/auth/httpauth/main.go
+++ b/auth/httpauth/main.go
@@ -104,10 +104,15 @@ func (c Config) getRefreshTokenCookieName() string {
 
 func (c Config) getAccessTokenCookieName() string {
 	return strs.Coalesce(c.AccessTokenCookieName, "token")
 }
 
+const defaultLoginEndpoint = "/api/auth/login"
+const defaultRefreshEndpoint = "/api/auth/refresh"
+const defaultLogoutEndpoint = "/api/auth/logout"
+const defaultRegisterEndpoint = "/api/auth/register"
+
 func Setup(router *res.Router, config Config) *AuthRouter {
 	loginPath := strs.Coalesce(config.LoginPath, defaultLoginEndpoint)
 	router.Post(loginPath, loginHandler(&config))
 	logoutPath := strs.Coalesce(config.LogoutPath, defaultLogoutEndpoint)
 	router.Post(logoutPath, logoutHandler(&config))
@@ -132,25 +137,31 @@ func Setup(router *res.Router, config Config) *AuthRouter {
 
 	if config.OAuth != nil {
 		oauth.Setup(router, config.OAuth, sessionSetter)
 	}
 
-	server := middleware(config)
+	server := newServer(config)
 
-	router.Use(func(h http.Handler) http.Handler {
-		server.next = h
-		return server
+	router.Use(func(handler http.Handler) http.Handler {
+		return cloneServer(server, handler)
 	})
 
 	return &AuthRouter{
 		config: &config,
 		auth:   server,
 		next:   router,
 	}
 }
 
-func middleware(config Config) *server {
+func cloneServer(src *server, next http.Handler) *server {
+	clone := &server{}
+	*clone = *src
+	clone.next = next
+	return clone
+}
+
+func newServer(config Config) *server {
 
 	if config.CredentialChecker == nil {
 		log.Fatal("github.com/ntbosscher/gobase/auth/authhttp.Middleware(config): config requires CredentialChecker")
 	}
 
@@ -161,22 +172,17 @@ func middleware(config Config) *server {
 		authHandler:              authHandler(&config),
 	}
 }
 
 type server struct {
-	next                     http.Handler
+	next http.Handler
 	perRequestFilter         PerRequestFilter
 	ignoreRoutesWithPrefixes []string
 	ignoreRoutes             []string
 	authHandler              func(request *res.Request) (res.Responder, context.Context)
 }
 
-const defaultLoginEndpoint = "/api/auth/login"
-const defaultRefreshEndpoint = "/api/auth/refresh"
-const defaultLogoutEndpoint = "/api/auth/logout"
-const defaultRegisterEndpoint = "/api/auth/register"
-
 func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 	ignoredRoute := false
 
 	for _, path := range s.ignoreRoutes {

Vulnerable code: 	server := middleware(config)
	router.Use(func(h http.Handler) http.Handler {
		server.next = h
		return server
func middleware(config Config) *server {
	next                     http.Handler
const defaultLoginEndpoint = "/api/auth/login"
const defaultRefreshEndpoint = "/api/auth/refresh"
const defaultLogoutEndpoint = "/api/auth/logout"
const defaultRegisterEndpoint = "/api/auth/register"

Fixed code: const defaultLoginEndpoint = "/api/auth/login"
const defaultRefreshEndpoint = "/api/auth/refresh"
const defaultLogoutEndpoint = "/api/auth/logout"
const defaultRegisterEndpoint = "/api/auth/register"

	server := newServer(config)
	router.Use(func(handler http.Handler) http.Handler {
		return cloneServer(server, handler)
func cloneServer(src *server, next http.Handler) *server {
	clone := &server{}
	*clone = *src
	clone.next = next
	return clone
}

func newServer(config Config) *server {
	next http.Handler