CVE-2023-37918 (published 2023-07-21T21:15Z)

Dapr is a portable, event-driven, runtime for building distributed applications across cloud and edge. A vulnerability has been found in Dapr that allows bypassing API token authentication, which is used by the Dapr sidecar to authenticate calls coming from the application, with a well-crafted HTTP request. Users who leverage API token authentication are encouraged to upgrade Dapr to 1.10.9 or to 1.11.2. This vulnerability impacts Dapr users who have configured API token authentication. An attacker could craft a request that is always allowed by the Dapr sidecar over HTTP, even if the `dapr-api-token` in the request is invalid or missing. The issue has been fixed in Dapr 1.10.9 or to 1.11.2. There are no known workarounds for this vulnerability.\n

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-287
cwe_name: Improper Authentication
description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
extended_description: 
            
			
         
         

Fix information:
repo_url: https://github.com/dapr/dapr
commit_details: repo_url: https://github.com/dapr/dapr
author: ItalyPaleAle
author_date: 2023-07-19 13:59:48-07:00
msg: Fixed API token authentication bypassed when path contains `/healthz`

The APITokenAuthMiddleware allowed bypassing the check if the path included `/healthz`. An attacker only needed to include `/healthz` in the URL, even the querystring, to bypass the API token check, for example `/v1.0/invoke/myapp/method/something?foo=/healthz`.

Additionally, this was not checking the method of the request, so requests to `POST /healthz` would cause a service invocation to happen.

This fixes the issue by making the check a lot more strict. The API token check can be bypassed only if:

- The path is exactly `/v1.0/healthz` or `/v1.0/healthz/outbound` (slashes are trimmed on each side)
- The method is `GET`

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
repository: repo_url: https://github.com/dapr/dapr
repo_name: dapr/dapr
description: Dapr is a portable, event-driven, runtime for building distributed applications across cloud and edge.
repo_language: Go
owner: dapr
file_changes: filename: v1.11.2.md
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,8 @@
 
 This update contains security fixes:
 
-  - [Security: Potential DoS in avro dependency (CVE-2023-37475)](#security-potential-dos-in-avro-dependency-cve-2023-37475)
+  - [Security: API token authentication bypass in HTTP endpoints](#security-api-token-authentication-bypass-in-http-endpoints) ([Security advisory](https://github.com/dapr/dapr/security/advisories/GHSA-59m6-82qm-vqgj))
+  - [Security: Potential DoS in avro dependency](#security-potential-dos-in-avro-dependency-cve-2023-37475) ([CVE-2023-37475](https://github.com/hamba/avro/security/advisories/GHSA-9x44-9pgq-cf45))
 
 Additionally, this patch release contains bug fixes:
 
@@ -10,6 +11,26 @@ Additionally, this patch release contains bug fixes:
   - [Fixed: Workflows not working in some Kubernetes clusters](#fixed-workflows-not-working-in-some-kubernetes-clusters)
   - [Fixed a number of bugs in the gRPC Configuration Subscribe API](#fixed-a-number-of-bugs-in-the-grpc-configuration-subscribe-api)
 
+## Security: API token authentication bypass in HTTP endpoints
+
+### Problem
+
+[Security advisory](https://github.com/dapr/dapr/security/advisories/GHSA-59m6-82qm-vqgj)
+
+A high-severity vulnerability has been found in Dapr that allows bypassing [API token authentication](https://docs.dapr.io/operations/security/api-token/), which is used by the Dapr sidecar to authenticate calls coming from the application, with a well-crafted HTTP request.
+
+### Impact
+
+The vulnerability impacts all users on Dapr <=1.10.9 and <=1.11.2 who are using API token authentication.
+
+### Root cause
+
+The Dapr sidecar allowed all requests containing `/healthz` in the URL (including query string) to bypass API token authentication.
+
+### Solution
+
+We have changed the API token authentication middleware to allow bypassing the authentication only for healthcheck endpoints more strictly.
+
 ## Security: Potential DoS in avro dependency (CVE-2023-37475)
 
 ### Problem

programming_language: Markdown
filename: server.go
change_type: ModificationType.MODIFY
diff: @@ -287,12 +287,29 @@ func useAPIAuthentication(next fasthttp.RequestHandler) fasthttp.RequestHandler
 
 	return func(ctx *fasthttp.RequestCtx) {
 		v := ctx.Request.Header.Peek(authConsts.APITokenHeader)
-		if auth.ExcludedRoute(string(ctx.Request.URI().FullURI())) || string(v) == token {
-			ctx.Request.Header.Del(authConsts.APITokenHeader)
-			next(ctx)
-		} else {
+		if string(v) != token && !isRouteExcludedFromAPITokenAuth(string(ctx.Request.Header.Method()), string(ctx.Request.URI().FullURI())) {
 			ctx.Error("invalid api token", http.StatusUnauthorized)
+			return
 		}
+
+		ctx.Request.Header.Del(authConsts.APITokenHeader)
+		next(ctx)
+	}
+}
+
+func isRouteExcludedFromAPITokenAuth(method string, urlString string) bool {
+	u, err := url.Parse(urlString)
+	if err != nil {
+		return false
+	}
+	path := strings.Trim(u.Path, "/")
+	switch path {
+	case apiVersionV1 + "/healthz":
+		return method == http.MethodGet
+	case apiVersionV1 + "/healthz/outbound":
+		return method == http.MethodGet
+	default:
+		return false
 	}
 }
 

programming_language: Go
filename: token.go
change_type: ModificationType.MODIFY
diff: @@ -15,13 +15,10 @@ package security
 
 import (
 	"os"
-	"strings"
 
 	"github.com/dapr/dapr/pkg/runtime/security/consts"
 )
 
-var excludedRoutes = []string{"/healthz"}
-
 // GetAPIToken returns the value of the api token from an environment variable.
 func GetAPIToken() string {
 	return os.Getenv(consts.APITokenEnvVar)
@@ -31,13 +28,3 @@ func GetAPIToken() string {
 func GetAppToken() string {
 	return os.Getenv(consts.AppAPITokenEnvVar)
 }
-
-// ExcludedRoute returns whether a given route should be excluded from a token check.
-func ExcludedRoute(route string) bool {
-	for _, r := range excludedRoutes {
-		if strings.Contains(route, r) {
-			return true
-		}
-	}
-	return false
-}

programming_language: Go
filename: token_test.go
change_type: ModificationType.MODIFY
diff: @@ -54,17 +54,3 @@ func TestAppToken(t *testing.T) {
 		assert.Equal(t, "", token)
 	})
 }
-
-func TestExcludedRoute(t *testing.T) {
-	t.Run("healthz route is excluded", func(t *testing.T) {
-		route := "v1.0/healthz"
-		excluded := ExcludedRoute(route)
-		assert.True(t, excluded)
-	})
-
-	t.Run("custom route is not excluded", func(t *testing.T) {
-		route := "v1.0/state"
-		excluded := ExcludedRoute(route)
-		assert.False(t, excluded)
-	})
-}

programming_language: Go