CVE-2023-28433 (Go, published 2023-03-22T21:15Z)
Description: value: Minio is a Multi-Cloud Object Storage framework. All users on Windows prior to version RELEASE.2023-03-20T20-16-18Z are impacted. MinIO fails to filter the `\` character, which allows for arbitrary object placement across buckets. As a result, a user with low privileges, such as an access key, service account, or STS credential, which only has permission to `PutObject` in a specific bucket, can create an admin user. This issue is patched in RELEASE.2023-03-20T20-16-18Z. There are no known workarounds.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/minio/minio
Files changed:
cmd/object-api-multipart_test.go
cmd/object-api-utils.go
cmd/object-api-utils_test.go
Commit message: reject object names with '\' on windows (#16856)



Vulnerable code:
		{bucket, "\\", uploadID, InvalidUploadID{}},
	if strings.ContainsRune(object, 0) {
		return false
	}
	return true
		if strings.ContainsAny(object, `:*?"|<>`) {

Fixed code:
	"runtime"
	if runtime.GOOS == globalWindowsOSName {
		t.Skip()
	}

	if runtime.GOOS != globalWindowsOSName {
		abortTestCases = append(abortTestCases, struct {
			bucketName      string
			objName         string
			uploadID        string
			expectedErrType error
		}{bucket, "\\", uploadID, InvalidUploadID{}})
	}

	return !strings.ContainsRune(object, 0)
		if strings.ContainsAny(object, `\:*?"|<>`) {
	"context"
	"net/http/httptest"
	"runtime"
	"github.com/minio/minio/internal/auth"
// Wrapper
func TestPathTraversalExploit(t *testing.T) {
	if runtime.GOOS != globalWindowsOSName {
		t.Skip()
	}
	defer DetectTestLeak(t)()
	ExecExtendedObjectLayerAPITest(t, testPathTraversalExploit, []string{"PutObject"})
}

// testPathTraversal exploit test, exploits path traversal on windows
// with following object names "\\../.minio.sys/config/iam/${username}/identity.json"
// #16852
func testPathTraversalExploit(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
	credentials auth.Credentials, t *testing.T,
) {
	if err := newTestConfig(globalMinioDefaultRegion, obj); err != nil {
		t.Fatalf("Initializing config.json failed")
	}

	objectName := `\../.minio.sys/config/hello.txt`

	// initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
	rec := httptest.NewRecorder()
	// construct HTTP request for Get Object end point.
	req, err := newTestSignedRequestV4(http.MethodPut, getPutObjectURL("", bucketName, objectName),
		int64(5), bytes.NewReader([]byte("hello")), credentials.AccessKey, credentials.SecretKey, map[string]string{})
	if err != nil {
		t.Fatalf("failed to create HTTP request for Put Object: <ERROR> %v", err)
	}

	// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
	// Call the ServeHTTP to execute the handler.
	apiRouter.ServeHTTP(rec, req)

	ctx, cancel := context.WithCancel(GlobalContext)
	defer cancel()

	// Now check if we actually wrote to backend (regardless of the response
	// returned by the server).
	z := obj.(*erasureServerPools)
	xl := z.serverPools[0].sets[0]
	erasureDisks := xl.getDisks()
	parts, errs := readAllFileInfo(ctx, erasureDisks, bucketName, objectName, "", false)
	for i := range parts {
		if errs[i] == nil {
			if parts[i].Name == objectName {
				t.Errorf("path traversal allowed to allow writing to minioMetaBucket: %s", instanceType)
			}
		}
	}
}