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

CVE-2020-12758

CVE-2020-12758

Description

HashiCorp Consul and Consul Enterprise could crash when configured with an abnormally-formed service-router entry. Introduced in 1.6.0, fixed in 1.6.6 and 1.7.4.

AI Insight

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

HashiCorp Consul and Consul Enterprise can crash when a service-router entry without a destination is configured.

Vulnerability

Analysis

CVE-2020-12758 is a denial-of-service vulnerability in HashiCorp Consul and Consul Enterprise. The vulnerability arises from a flaw in how Consul processes service-router configuration entries. When an administrator configures a service-router entry that is missing a destination field, the Consul server can crash. This crash occurs because the server does not properly handle the malformed entry, leading to a panic or similar fatal error [2][3]. The issue was introduced in Consul version 1.6.0 [3].

Exploitation

An attacker with the capability to modify service-router configurations (requiring service:write permissions) can trigger this vulnerability. By submitting a service-router entry that lacks a destination specification, the attacker can cause the Consul server to crash. This attack is performed through the service configuration API [2]. The crash is immediate upon processing the malformed entry.

Impact

Successful exploitation results in a denial of service. The Consul server crashes, which can disrupt service discovery, health checking, and other critical infrastructure functions in environments relying on Consul. This can lead to cascading failures in microservices architectures where Consul is used as the service mesh control plane.

Mitigation

HashiCorp has fixed this vulnerability in Consul versions 1.6.6 and 1.7.4. The fix, implemented in commit 69b44fb, ensures that when a service-router entry without a destination is encountered, Consul constructs a default destination instead of crashing [4]. Users are advised to upgrade to the patched versions immediately. No workarounds are provided, and the vulnerability is not known to be exploited in the wild per available sources.

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
69b44fb9424c

Construct a default destination if one does not exist for service-router (#7783)

https://github.com/hashicorp/consulChris PirainoMay 5, 2020via ghsa
2 files changed · +69 1
  • agent/consul/discoverychain/compile.go+6 1 modified
    @@ -552,7 +552,12 @@ func (c *compiler) assembleChain() error {
     		routeNode.Routes = append(routeNode.Routes, compiledRoute)
     
     		dest := route.Destination
    -
    +		if dest == nil {
    +			dest = &structs.ServiceRouteDestination{
    +				Service:   c.serviceName,
    +				Namespace: router.NamespaceOrDefault(),
    +			}
    +		}
     		svc := defaultIfEmpty(dest.Service, c.serviceName)
     		destNamespace := defaultIfEmpty(dest.Namespace, router.NamespaceOrDefault())
     
    
  • agent/consul/discoverychain/compile_test.go+63 0 modified
    @@ -28,6 +28,7 @@ func TestCompile(t *testing.T) {
     		"router with defaults and resolver":                testcase_RouterWithDefaults_NoSplit_WithResolver(),
     		"router with defaults and noop split":              testcase_RouterWithDefaults_WithNoopSplit_DefaultResolver(),
     		"router with defaults and noop split and resolver": testcase_RouterWithDefaults_WithNoopSplit_WithResolver(),
    +		"router with no destination":                       testcase_JustRouterWithNoDestination(),
     		"route bypasses splitter":                          testcase_RouteBypassesSplit(),
     		"noop split":                                       testcase_NoopSplit_DefaultResolver(),
     		"noop split with protocol from proxy defaults":     testcase_NoopSplit_DefaultResolver_ProtocolFromProxyDefaults(),
    @@ -184,6 +185,68 @@ func testcase_JustRouterWithDefaults() compileTestCase {
     	return compileTestCase{entries: entries, expect: expect}
     }
     
    +func testcase_JustRouterWithNoDestination() compileTestCase {
    +	entries := newEntries()
    +	setServiceProtocol(entries, "main", "http")
    +
    +	entries.AddRouters(
    +		&structs.ServiceRouterConfigEntry{
    +			Kind: "service-router",
    +			Name: "main",
    +			Routes: []structs.ServiceRoute{
    +				{
    +					Match: &structs.ServiceRouteMatch{
    +						HTTP: &structs.ServiceRouteHTTPMatch{
    +							PathPrefix: "/",
    +						},
    +					},
    +				},
    +			},
    +		},
    +	)
    +
    +	expect := &structs.CompiledDiscoveryChain{
    +		Protocol:  "http",
    +		StartNode: "router:main.default",
    +		Nodes: map[string]*structs.DiscoveryGraphNode{
    +			"router:main.default": &structs.DiscoveryGraphNode{
    +				Type: structs.DiscoveryGraphNodeTypeRouter,
    +				Name: "main.default",
    +				Routes: []*structs.DiscoveryRoute{
    +					{
    +						Definition: &structs.ServiceRoute{
    +							Match: &structs.ServiceRouteMatch{
    +								HTTP: &structs.ServiceRouteHTTPMatch{
    +									PathPrefix: "/",
    +								},
    +							},
    +						},
    +						NextNode: "resolver:main.default.dc1",
    +					},
    +					{
    +						Definition: newDefaultServiceRoute("main", "default"),
    +						NextNode:   "resolver:main.default.dc1",
    +					},
    +				},
    +			},
    +			"resolver:main.default.dc1": &structs.DiscoveryGraphNode{
    +				Type: structs.DiscoveryGraphNodeTypeResolver,
    +				Name: "main.default.dc1",
    +				Resolver: &structs.DiscoveryResolver{
    +					Default:        true,
    +					ConnectTimeout: 5 * time.Second,
    +					Target:         "main.default.dc1",
    +				},
    +			},
    +		},
    +		Targets: map[string]*structs.DiscoveryTarget{
    +			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),
    +		},
    +	}
    +
    +	return compileTestCase{entries: entries, expect: expect}
    +}
    +
     func testcase_RouterWithDefaults_NoSplit_WithResolver() compileTestCase {
     	entries := newEntries()
     	setServiceProtocol(entries, "main", "http")
    

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.