CVE-2021-21287 (Go, published 2021-02-01T18:15Z)
Description: value: MinIO is a High Performance Object Storage released under Apache License v2.0. In MinIO before version RELEASE.2021-01-30T00-20-58Z there is a server-side request forgery vulnerability. The target application may have functionality for importing data from a URL, publishing data to a URL, or otherwise reading data from a URL that can be tampered with. The attacker modifies the calls to this functionality by supplying a completely different URL or by manipulating how URLs are built (path traversal etc.). In a Server-Side Request Forgery (SSRF) attack, the attacker can abuse functionality on the server to read or update internal resources. The attacker can supply or modify a URL which the code running on the server will read or submit data, and by carefully selecting the URLs, the attacker may be able to read server configuration such as AWS metadata, connect to internal services like HTTP enabled databases, or perform post requests towards internal services which are not intended to be exposed. This is fixed in version RELEASE.2021-01-30T00-20-58Z, all users are advised to upgrade. As a workaround you can disable the browser front-end with "MINIO_BROWSER=off" environment variable.
Severity: MEDIUM (CVSS v3 base score: 7.7)
Weakness: CWE-918 \u2014 Server-Side Request Forgery (SSRF)
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
Repository: https://github.com/minio/minio
Files changed:
cmd/api-errors.go
cmd/web-handlers.go
Commit message: fix: LoginSTS should be an inline implementation (#11337)

STS tokens can be obtained by using local APIs
once the remote JWT token is presented, current
code was not validating the incoming token in the
first place and was incorrectly making a network
operation using that token.

For the most part this always works without issues,
but under adversarial scenarios it exposes client
to hand-craft a request that can reach internal
services without authentication.

This kind of proxying should be avoided before
validating the incoming token.

Vulnerable code:
	"encoding/xml"
	v := url.Values{}
	v.Set("Action", webIdentity)
	v.Set("WebIdentityToken", args.Token)
	v.Set("Version", stsAPIVersion)

	scheme := "http"
	if sourceScheme := handlers.GetSourceScheme(r); sourceScheme != "" {
		scheme = sourceScheme
	}
	if globalIsTLS {
		scheme = "https"
	u := &url.URL{
		Scheme: scheme,
		Host:   r.Host,
	u.RawQuery = v.Encode()

	req, err := http.NewRequest(http.MethodPost, u.String(), nil)
	clnt := &http.Client{
		Transport: NewGatewayHTTPTransport(),
	resp, err := clnt.Do(req)
	defer xhttp.DrainBody(resp.Body)
	if resp.StatusCode != http.StatusOK {
		return toJSONError(ctx, errors.New(resp.Status))
	a := AssumeRoleWithWebIdentityResponse{}
	if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil {
		return toJSONError(ctx, err)
	reply.Token = a.Result.Credentials.SessionToken

Fixed code:
		default:
			apiErr = APIError{
				Code:           apiErr.Code,
				Description:    fmt.Sprintf("%s: cause(%v)", apiErr.Description, err),
				HTTPStatusCode: apiErr.HTTPStatusCode,
			}
var errSTSNotInitialized = errors.New("STS API not initialized, please configure STS support")

	if globalOpenIDValidators == nil {
		return toJSONError(ctx, errSTSNotInitialized)
	v, err := globalOpenIDValidators.Get("jwt")
	if err != nil {
		logger.LogIf(ctx, err)
		return toJSONError(ctx, errSTSNotInitialized)
	m, err := v.Validate(args.Token, "")
	// JWT has requested a custom claim with policy value set.
	// This is a MinIO STS API specific value, this value should
	// be set and configured on your identity provider as part of
	// JWT custom claims.
	var policyName string
	policySet, ok := iampolicy.GetPoliciesFromClaims(m, iamPolicyClaimNameOpenID())
	if ok {
		policyName = globalIAMSys.CurrentPolicies(strings.Join(policySet.ToSlice(), ","))
	if policyName == "" && globalPolicyOPA == nil {
		return toJSONError(ctx, fmt.Errorf("%s claim missing from the JWT token, credentials will not be generated", iamPolicyClaimNameOpenID()))
	}
	m[iamPolicyClaimNameOpenID()] = policyName

	secret := globalActiveCred.SecretKey
	cred, err := auth.GetNewCredentialsWithMetadata(m, secret)
	// Set the newly generated credentials.
	if err = globalIAMSys.SetTempUser(cred.AccessKey, cred, policyName); err != nil {
		return toJSONError(ctx, err)
	// Notify all other MinIO peers to reload temp users
	for _, nerr := range globalNotificationSys.LoadUser(cred.AccessKey, true) {
		if nerr.Err != nil {
			logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
			logger.LogIf(ctx, nerr.Err)
		}
	reply.Token = cred.SessionToken
	case errSTSNotInitialized:
		return APIError(stsErrCodes.ToSTSErr(ErrSTSNotInitialized))