CVE-2022-35919 (Go, published 2022-08-01T22:15Z)
Description: value: MinIO is a High Performance Object Storage released under GNU Affero General Public License v3.0. In affected versions all 'admin' users authorized for `admin:ServerUpdate` can selectively trigger an error that in response, returns the content of the path requested. Any normal OS system would allow access to contents at any arbitrary paths that are readable by MinIO process. Users are advised to upgrade. Users unable to upgrade may disable ServerUpdate API by denying the `admin:ServerUpdate` action for your admin users via IAM policies.
Severity: nan (CVSS v3 base score: 2.7)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/minio/minio
Files changed:
cmd/update.go
Commit message: do not allow filesystem fallback in server download (#15429)

It is possible for anyone with admin access to relatively
to get any content of any random OS location by simply
providing the file with 'mc admin update alias/ /etc/passwd`.

Workaround is to disable 'admin:ServiceUpdate' action. Everyone
is advised to upgrade to this patch.

Thanks to @alevsk for finding this bug.

Vulnerable code:
	var reader io.ReadCloser
	if u.Scheme == "https" || u.Scheme == "http" {
		req, err := http.NewRequest(http.MethodGet, u.String(), nil)
		if err != nil {
			return content, AdminError{
				Code:       AdminUpdateUnexpectedFailure,
				Message:    err.Error(),
				StatusCode: http.StatusInternalServerError,
			}
		req.Header.Set("User-Agent", getUserAgent(mode))
		client := &http.Client{Transport: getUpdateTransport(timeout)}
		resp, err := client.Do(req)
		if err != nil {
			if xnet.IsNetworkOrHostDown(err, false) {
				return content, AdminError{
					Code:       AdminUpdateURLNotReachable,
					Message:    err.Error(),
					StatusCode: http.StatusServiceUnavailable,
				}
			}
				Code:       AdminUpdateUnexpectedFailure,
				StatusCode: http.StatusInternalServerError,
		if resp == nil {
			return content, AdminError{
				Code:       AdminUpdateUnexpectedFailure,
				Message:    fmt.Sprintf("No response from server to download URL %s", u),
				StatusCode: http.StatusInternalServerError,
			}
		reader = resp.Body
		defer xhttp.DrainBody(resp.Body)

		if resp.StatusCode != http.StatusOK {
			return content, AdminError{
				Code:       AdminUpdateUnexpectedFailure,
				Message:    fmt.Sprintf("Error downloading URL %s. Response: %v", u, resp.Status),
				StatusCode: resp.StatusCode,
			}
	} else {
		reader, err = os.Open(u.Path)
		if err != nil {
			return content, AdminError{
				Code:       AdminUpdateURLNotReachable,
				Message:    err.Error(),
				StatusCode: http.StatusServiceUnavailable,
			}
	contentBytes, err := ioutil.ReadAll(reader)

Fixed code:
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return content, AdminError{
			Code:       AdminUpdateUnexpectedFailure,
			Message:    err.Error(),
			StatusCode: http.StatusInternalServerError,
	}
	req.Header.Set("User-Agent", getUserAgent(mode))
	client := &http.Client{Transport: getUpdateTransport(timeout)}
	resp, err := client.Do(req)
	if err != nil {
		if xnet.IsNetworkOrHostDown(err, false) {
				Code:       AdminUpdateURLNotReachable,
				StatusCode: http.StatusServiceUnavailable,
		return content, AdminError{
			Code:       AdminUpdateUnexpectedFailure,
			Message:    err.Error(),
			StatusCode: http.StatusInternalServerError,
	}
	if resp == nil {
		return content, AdminError{
			Code:       AdminUpdateUnexpectedFailure,
			Message:    fmt.Sprintf("No response from server to download URL %s", u),
			StatusCode: http.StatusInternalServerError,
	}
	defer xhttp.DrainBody(resp.Body)

	if resp.StatusCode != http.StatusOK {
		return content, AdminError{
			Code:       AdminUpdateUnexpectedFailure,
			Message:    fmt.Sprintf("Error downloading URL %s. Response: %v", u, resp.Status),
			StatusCode: resp.StatusCode,
	contentBytes, err := ioutil.ReadAll(resp.Body)