VYPR
Critical severityNVD Advisory· Published Mar 18, 2023· Updated Feb 26, 2025

CVE-2023-28609

CVE-2023-28609

Description

api/auth.go in Ansible Semaphore before 2.8.89 mishandles authentication.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Ansible Semaphore before 2.8.89 has an authentication bypass in api/auth.go because the authentication handler does not return a boolean to indicate failure, allowing unauthorized access.

The vulnerability resides in api/auth.go where the authenticationHandler function did not return a boolean value to indicate whether authentication succeeded. Instead, it only wrote HTTP status codes and returned without a value, meaning the caller could not distinguish between success and failure. This allowed requests to proceed even after authentication failures.

An attacker can exploit this by sending requests with invalid or missing authentication tokens. The server would write an unauthorized status but continue processing the request because the handler's return value was ignored. No special network position is required; the attacker only needs to be able to send HTTP requests to the Semaphore API.

Successful exploitation allows an attacker to bypass authentication entirely, gaining unauthorized access to Semaphore's API endpoints. This could lead to reading sensitive data, executing tasks (e.g., Ansible playbooks), or modifying configurations, depending on the permissions of the unauthenticated context.

The issue was fixed in version 2.8.89 by changing the function signature to return a boolean and ensuring that the caller checks this value before proceeding [1][4]. Users should upgrade to at least this version. No workarounds are documented.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/ansible-semaphore/semaphoreGo
< 2.8.892.8.89

Affected products

2

Patches

1
3e4a62b7f2b1

fix: authentization bug

https://github.com/ansible-semaphore/semaphoreDenis GukovMar 13, 2023via ghsa
2 files changed · +21 22
  • api/auth.go+21 14 modified
    @@ -11,7 +11,7 @@ import (
     	"time"
     )
     
    -func authenticationHandler(w http.ResponseWriter, r *http.Request) {
    +func authenticationHandler(w http.ResponseWriter, r *http.Request) bool {
     	var userID int
     
     	authHeader := strings.ToLower(r.Header.Get("authorization"))
    @@ -25,7 +25,7 @@ func authenticationHandler(w http.ResponseWriter, r *http.Request) {
     			}
     
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     
     		userID = token.UserID
    @@ -34,20 +34,20 @@ func authenticationHandler(w http.ResponseWriter, r *http.Request) {
     		cookie, err := r.Cookie("semaphore")
     		if err != nil {
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     
     		value := make(map[string]interface{})
     		if err = util.Cookie.Decode("semaphore", cookie.Value, &value); err != nil {
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     
     		user, ok := value["user"]
     		sessionVal, okSession := value["session"]
     		if !ok || !okSession {
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     
     		userID = user.(int)
    @@ -58,7 +58,7 @@ func authenticationHandler(w http.ResponseWriter, r *http.Request) {
     
     		if err != nil {
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     
     		if time.Since(session.LastActive).Hours() > 7*24 {
    @@ -70,13 +70,13 @@ func authenticationHandler(w http.ResponseWriter, r *http.Request) {
     			}
     
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     
     		if err := helpers.Store(r).TouchSession(userID, sessionID); err != nil {
     			log.Error(err)
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     	}
     
    @@ -87,26 +87,29 @@ func authenticationHandler(w http.ResponseWriter, r *http.Request) {
     			log.Error(err)
     		}
     		w.WriteHeader(http.StatusUnauthorized)
    -		return
    +		return false
     	}
     
     	if util.Config.DemoMode {
     		if !user.Admin && r.Method != "GET" &&
     			!strings.HasSuffix(r.URL.Path, "/tasks") &&
     			!strings.HasSuffix(r.URL.Path, "/stop") {
     			w.WriteHeader(http.StatusUnauthorized)
    -			return
    +			return false
     		}
     	}
     
     	context.Set(r, "user", &user)
    +	return true
     }
     
     // nolint: gocyclo
     func authentication(next http.Handler) http.Handler {
     	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    -		authenticationHandler(w, r)
    -		next.ServeHTTP(w, r)
    +		ok := authenticationHandler(w, r)
    +		if ok {
    +			next.ServeHTTP(w, r)
    +		}
     	})
     }
     
    @@ -115,10 +118,14 @@ func authenticationWithStore(next http.Handler) http.Handler {
     	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     		store := helpers.Store(r)
     
    +		var ok bool
    +		
     		db.StoreSession(store, r.URL.String(), func() {
    -			authenticationHandler(w, r)
    +			ok = authenticationHandler(w, r)
     		})
     
    -		next.ServeHTTP(w, r)
    +		if ok {
    +			next.ServeHTTP(w, r)
    +		}
     	})
     }
    
  • api/router.go+0 8 modified
    @@ -348,16 +348,8 @@ func servePublic(w http.ResponseWriter, r *http.Request) {
     }
     
     func getSystemInfo(w http.ResponseWriter, r *http.Request) {
    -	//updateAvailable, err := util.CheckUpdate()
    -
    -	//if err != nil {
    -	//	helpers.WriteError(w, err)
    -	//	return
    -	//}
    -
     	body := map[string]interface{}{
     		"version": util.Version,
    -		//"update":  updateAvailable,
     		"ansible": util.AnsibleVersion(),
     		"demo":    util.Config.DemoMode,
     	}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.