VYPR
Moderate severityNVD Advisory· Published Jun 11, 2020· Updated Aug 4, 2024

CVE-2020-13170

CVE-2020-13170

Description

HashiCorp Consul and Consul Enterprise did not appropriately enforce scope for local tokens issued by a primary data center, where replication to a secondary data center was not enabled. Introduced in 1.4.0, fixed in 1.6.6 and 1.7.4.

AI Insight

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

In HashiCorp Consul, local ACL tokens from a primary datacenter could be used in secondary datacenters without replication, allowing privilege escalation.

Vulnerability

CVE-2020-13170 is a security flaw in HashiCorp Consul and Consul Enterprise, where the ACL system failed to enforce that local tokens issued by a primary datacenter should only be resolvable within that datacenter when replication to secondary datacenters is not enabled. This issue was introduced in Consul version 1.4.0 and affects all subsequent versions until the fix in 1.6.6 and 1.7.4 [1][2].

Exploitation

An attacker who possesses a valid local ACL token from a primary datacenter can use that token to authenticate against a secondary datacenter that does not have replication enabled. The vulnerability arises because Consul previously resolved tokens without checking whether the token was local to the datacenter it originated from, as shown in the fix that adds a check for resp.Token.Local and SourceDatacenter [4].

Impact

Successful exploitation allows an attacker to potentially gain unauthorized access and privileges in secondary datacenters, bypassing ACL restrictions. This could lead to unauthorized operations such as reading or modifying configuration data, disrupting service discovery, or accessing sensitive information within the secondary datacenter.

Mitigation

HashiCorp has addressed this vulnerability in Consul versions 1.6.6 and 1.7.4 [1][2]. Users are strongly advised to upgrade to these or later versions. There is no known workaround; applying the patch is the recommended course of action.

AI Insight generated on May 21, 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/hashicorp/consulGo
>= 1.6.0-beta1, < 1.6.61.6.6
github.com/hashicorp/consulGo
>= 1.7.0, < 1.7.41.7.4

Affected products

3

Patches

1
242994a016a1

acl: do not resolve local tokens from remote dcs (#8068)

https://github.com/hashicorp/consulHans HasselbergJun 9, 2020via ghsa
4 files changed · +53 2
  • agent/consul/acl_endpoint.go+1 0 modified
    @@ -260,6 +260,7 @@ func (a *ACL) TokenRead(args *structs.ACLTokenGetRequest, reply *structs.ACLToke
     			}
     
     			reply.Index, reply.Token = index, token
    +			reply.SourceDatacenter = args.Datacenter
     			return nil
     		})
     }
    
  • agent/consul/acl.go+3 0 modified
    @@ -417,6 +417,9 @@ func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *struc
     		if resp.Token == nil {
     			r.cache.PutIdentity(cacheID, nil)
     			return nil, acl.ErrNotFound
    +		} else if resp.Token.Local && r.config.Datacenter != resp.SourceDatacenter {
    +			r.cache.PutIdentity(cacheID, nil)
    +			return nil, acl.PermissionDeniedError{Cause: fmt.Sprintf("This is a local token in datacenter %q", resp.SourceDatacenter)}
     		} else {
     			r.cache.PutIdentity(cacheID, resp.Token)
     			return resp.Token, nil
    
  • agent/consul/acl_test.go+46 0 modified
    @@ -3703,3 +3703,49 @@ func TestDedupeServiceIdentities(t *testing.T) {
     		})
     	}
     }
    +func TestACL_LocalToken(t *testing.T) {
    +	t.Run("local token in same dc", func(t *testing.T) {
    +		d := &ACLResolverTestDelegate{
    +			datacenter: "dc1",
    +			tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
    +				reply.Token = &structs.ACLToken{Local: true}
    +				// different dc
    +				reply.SourceDatacenter = "dc1"
    +				return nil
    +			},
    +		}
    +		r := newTestACLResolver(t, d, nil)
    +		_, err := r.fetchAndCacheIdentityFromToken("", nil)
    +		require.NoError(t, err)
    +	})
    +
    +	t.Run("non local token in remote dc", func(t *testing.T) {
    +		d := &ACLResolverTestDelegate{
    +			datacenter: "dc1",
    +			tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
    +				reply.Token = &structs.ACLToken{Local: false}
    +				// different dc
    +				reply.SourceDatacenter = "remote"
    +				return nil
    +			},
    +		}
    +		r := newTestACLResolver(t, d, nil)
    +		_, err := r.fetchAndCacheIdentityFromToken("", nil)
    +		require.NoError(t, err)
    +	})
    +
    +	t.Run("local token in remote dc", func(t *testing.T) {
    +		d := &ACLResolverTestDelegate{
    +			datacenter: "dc1",
    +			tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error {
    +				reply.Token = &structs.ACLToken{Local: true}
    +				// different dc
    +				reply.SourceDatacenter = "remote"
    +				return nil
    +			},
    +		}
    +		r := newTestACLResolver(t, d, nil)
    +		_, err := r.fetchAndCacheIdentityFromToken("", nil)
    +		require.Equal(t, acl.PermissionDeniedError{Cause: "This is a local token in datacenter \"remote\""}, err)
    +	})
    +}
    
  • agent/structs/acl.go+3 2 modified
    @@ -1258,8 +1258,9 @@ type ACLTokenBootstrapRequest struct {
     
     // ACLTokenResponse returns a single Token + metadata
     type ACLTokenResponse struct {
    -	Token    *ACLToken
    -	Redacted bool // whether the token's secret was redacted
    +	Token            *ACLToken
    +	Redacted         bool // whether the token's secret was redacted
    +	SourceDatacenter string
     	QueryMeta
     }
     
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.