CVE-2018-19653
Description
HashiCorp Consul 0.5.1 through 1.4.0 can use cleartext agent-to-agent RPC communication because the verify_outgoing setting is improperly documented. NOTE: the vendor has provided reconfiguration steps that do not require a software upgrade.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
HashiCorp Consul 0.5.1–1.4.0 may use cleartext agent-to-agent RPC because the `verify_outgoing` setting is improperly documented.
Vulnerability
HashiCorp Consul versions 0.5.1 through 1.4.0 can use cleartext agent-to-agent RPC communication when the verify_outgoing configuration option is not explicitly enabled. The vulnerability arises because the documentation for verify_outgoing was ambiguous or insufficiently clear, causing operators to inadvertently leave agent-to-agent RPC unencrypted [1].
Exploitation
An attacker who is on the network path between two Consul agents can passively observe or actively manipulate unencrypted RPC traffic. No authentication or special privileges are required beyond network access to the communication channel. The attacker does not need to initiate a connection; simply eavesdropping on the RPC stream is sufficient to capture sensitive data [1].
Impact
Successful exploitation results in disclosure of confidential information transmitted via agent-to-agent RPC, including ACL tokens, service registration details, and other operational data. This can lead to further compromise of the Consul cluster, as captured tokens may be reused for unauthorized actions [1]. The impact is primarily a breach of confidentiality.
Mitigation
The vendor has provided reconfiguration steps that do not require a software upgrade. Specifically, operators should set both verify_outgoing and verify_server_hostname to true in the agent configuration, and ensure TLS certificates are properly distributed. This remediates the cleartext communication issue without upgrading the Consul binary [1][4]. A documentation fix clarifying the behavior was merged in the commit referenced in [2]. Affected versions include Consul 0.5.1 through 1.4.0.
AI Insight generated on May 22, 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.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/hashicorp/consulGo | >= 0.5.1, < 1.4.1 | 1.4.1 |
Affected products
7- osv-coords7 versionspkg:apk/chainguard/k3dpkg:apk/chainguard/k3d-proxypkg:apk/chainguard/k3d-toolspkg:apk/wolfi/k3dpkg:apk/wolfi/k3d-proxypkg:apk/wolfi/k3d-toolspkg:golang/github.com/hashicorp/consul
< 5.6.0-r11+ 6 more
- (no CPE)range: < 5.6.0-r11
- (no CPE)range: < 5.6.0-r11
- (no CPE)range: < 5.6.0-r11
- (no CPE)range: < 5.6.0-r11
- (no CPE)range: < 5.6.0-r11
- (no CPE)range: < 5.6.0-r11
- (no CPE)range: >= 0.5.1, < 1.4.1
Patches
1b64e8b262f80Documentation and changes for `verify_server_hostname` (#5069)
6 files changed · +86 −22
agent/config/builder.go+14 −2 modified@@ -613,6 +613,18 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) { enableRemoteScriptChecks := b.boolVal(c.EnableScriptChecks) enableLocalScriptChecks := b.boolValWithDefault(c.EnableLocalScriptChecks, enableRemoteScriptChecks) + // VerifyServerHostname implies VerifyOutgoing + verifyServerName := b.boolVal(c.VerifyServerHostname) + verifyOutgoing := b.boolVal(c.VerifyOutgoing) + if verifyServerName { + // Setting only verify_server_hostname is documented to imply + // verify_outgoing. If it doesn't then we risk sending communication over TCP + // when we documented it as forcing TLS for RPCs. Enforce this here rather + // than in several different places through the code that need to reason + // about it. (See CVE-2018-19653) + verifyOutgoing = true + } + // ---------------------------------------------------------------- // build runtime config // @@ -840,8 +852,8 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) { VerifyIncoming: b.boolVal(c.VerifyIncoming), VerifyIncomingHTTPS: b.boolVal(c.VerifyIncomingHTTPS), VerifyIncomingRPC: b.boolVal(c.VerifyIncomingRPC), - VerifyOutgoing: b.boolVal(c.VerifyOutgoing), - VerifyServerHostname: b.boolVal(c.VerifyServerHostname), + VerifyOutgoing: verifyOutgoing, + VerifyServerHostname: verifyServerName, Watches: c.Watches, }
agent/config/runtime_test.go+18 −0 modified@@ -2619,6 +2619,24 @@ func TestConfigFlagsAndEdgecases(t *testing.T) { } }, }, + { + // This tests checks that VerifyServerHostname implies VerifyOutgoing + desc: "verify_server_hostname implies verify_outgoing", + args: []string{ + `-data-dir=` + dataDir, + }, + json: []string{`{ + "verify_server_hostname": true + }`}, + hcl: []string{` + verify_server_hostname = true + `}, + patch: func(rt *RuntimeConfig) { + rt.DataDir = dataDir + rt.VerifyServerHostname = true + rt.VerifyOutgoing = true + }, + }, } testConfig(t, tests, dataDir)
tlsutil/config.go+0 −4 modified@@ -125,10 +125,6 @@ func (c *Config) KeyPair() (*tls.Certificate, error) { // requests. It will return a nil config if this configuration should // not use TLS for outgoing connections. func (c *Config) OutgoingTLSConfig() (*tls.Config, error) { - // If VerifyServerHostname is true, that implies VerifyOutgoing - if c.VerifyServerHostname { - c.VerifyOutgoing = true - } if !c.UseTLS && !c.VerifyOutgoing { return nil, nil }
tlsutil/config_test.go+4 −0 modified@@ -153,6 +153,7 @@ func TestConfig_OutgoingTLS_ServerName(t *testing.T) { func TestConfig_OutgoingTLS_VerifyHostname(t *testing.T) { conf := &Config{ + VerifyOutgoing: true, VerifyServerHostname: true, CAFile: "../test/ca/root.cer", } @@ -263,6 +264,7 @@ func TestConfig_outgoingWrapper_OK(t *testing.T) { CertFile: "../test/hostname/Alice.crt", KeyFile: "../test/hostname/Alice.key", VerifyServerHostname: true, + VerifyOutgoing: true, Domain: "consul", } @@ -297,6 +299,7 @@ func TestConfig_outgoingWrapper_BadDC(t *testing.T) { CertFile: "../test/hostname/Alice.crt", KeyFile: "../test/hostname/Alice.key", VerifyServerHostname: true, + VerifyOutgoing: true, Domain: "consul", } @@ -329,6 +332,7 @@ func TestConfig_outgoingWrapper_BadCert(t *testing.T) { CertFile: "../test/key/ourdomain.cer", KeyFile: "../test/key/ourdomain.key", VerifyServerHostname: true, + VerifyOutgoing: true, Domain: "consul", }
website/source/docs/agent/options.html.md+28 −12 modified@@ -203,7 +203,7 @@ will exit with an error at startup. whether [health checks that execute scripts](/docs/agent/checks.html) are enabled on this agent, and defaults to `false` so operators must opt-in to allowing these. This was added in Consul 0.9.0. - + ~> **Security Warning:** Enabling script checks in some configurations may introduce a remote execution vulnerability which is known to be targeted by malware. We strongly recommend `-enable-local-script-checks` instead. See [this @@ -596,9 +596,9 @@ default will automatically work with some tooling. The ACL token used to authorize secondary datacenters with the primary datacenter for replication operations. This token is required for servers outside the [`primary_datacenter`](#primary_datacenter) when ACLs are enabled. This token may be provided later using the [agent token API](/api/agent.html#update-acl-tokens) - on each server. This token must have at least "read" permissions on ACL data but if ACL - token replication is enabled then it must have "write" permissions. This also enables - Connect replication in Consul Enterprise, for which the token will require both operator + on each server. This token must have at least "read" permissions on ACL data but if ACL + token replication is enabled then it must have "write" permissions. This also enables + Connect replication in Consul Enterprise, for which the token will require both operator "write" and intention "read" permissions for replicating CA and Intention data. * <a name="acl_datacenter"></a><a href="#acl_datacenter">`acl_datacenter`</a> - **This field is @@ -1595,19 +1595,35 @@ default will automatically work with some tooling. default, HTTPS is disabled. * <a name="verify_outgoing"></a><a href="#verify_outgoing">`verify_outgoing`</a> - If set to - true, Consul requires that all outgoing connections + true, Consul requires that all outgoing connections from this agent make use of TLS and that the server provides a certificate that is signed by a Certificate Authority from the [`ca_file`](#ca_file) or [`ca_path`](#ca_path). By default, this is false, and Consul will not make use of TLS for outgoing connections. This applies to clients and servers as both will make outgoing connections. -* <a name="verify_server_hostname"></a><a href="#verify_server_hostname">`verify_server_hostname`</a> - If set to - true, Consul verifies for all outgoing connections that the TLS certificate presented by the servers - matches "server.<datacenter>.<domain>" hostname. This implies `verify_outgoing`. - By default, this is false, and Consul does not verify the hostname of the certificate, only - that it is signed by a trusted CA. This setting is important to prevent a compromised - client from being restarted as a server, and thus being able to perform a MITM attack - or to be added as a Raft peer. This is new in 0.5.1. + ~> **Security Note:** Note that servers that specify `verify_outgoing = + true` will always talk to other servers over TLS, but they still _accept_ + non-TLS connections to allow for a transition of all clients to TLS. + Currently the only way to enforce that no client can communicate with a + server unencrypted is to also enable `verify_incoming` which requires client + certificates too. + +* <a name="verify_server_hostname"></a><a + href="#verify_server_hostname">`verify_server_hostname`</a> - If set to true, + Consul verifies for all outgoing TLS connections that the TLS certificate + presented by the servers matches "server.<datacenter>.<domain>" + hostname. By default, this is false, and Consul does not verify the hostname + of the certificate, only that it is signed by a trusted CA. This setting is + _critical_ to prevent a compromised client from being restarted as a server + and having all cluster state _including all ACL tokens and Connect CA root keys_ + replicated to it. This is new in 0.5.1. + + ~> **Security Note:** From versions 0.5.1 to 1.4.0, due to a bug, setting + this flag alone _does not_ imply `verify_outgoing` and leaves client to server + and server to server RPCs unencrypted despite the documentation stating otherwise. See + [CVE-2018-19653](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19653) + for more details. For those versions you **must also set `verify_outgoing = + true`** to ensure encrypted RPC connections. * <a name="watches"></a><a href="#watches">`watches`</a> - Watches is a list of watch specifications which allow an external process to be automatically invoked when a
website/source/docs/internals/security.html.md+22 −4 modified@@ -47,10 +47,21 @@ items outside of Consul's threat model as noted in sections below. * **Encryption enabled.** TCP and UDP encryption must be enabled and configured to prevent plaintext communication between Consul agents. At a minimum, - verify_outgoing should be enabled to verify server authenticity with each - server having a unique TLS certificate. verify_incoming provides additional - agent verification, but shouldn't directly affect the threat model since - requests must also contain a valid ACL token. + `verify_outgoing` should be enabled to verify server authenticity with each + server having a unique TLS certificate. `verify_server_hostname` is also + required to prevent a compromised agent restarting as a server and being given + access to all secrets. + + `verify_incoming` provides additional agent verification via mutual + authentication, but isn't _strictly_ necessary to enforce the threat model + since requests must also contain a valid ACL token. The subtlety is that + currently `verify_incoming = false` will allow servers to still accept + un-encrypted connections from clients (to allow for gradual TLS rollout). That + alone doesn't violate the threat model, but any misconfigured client that + chooses not to use TLS will violate the model. We recommend setting this to + true. If it is left as false care must be taken to ensure all consul clients + use `verify_outgoing = true` as noted above, but also all external API/UI + access must be via HTTPS with HTTP listeners disabled. ### Known Insecure Configurations @@ -74,6 +85,13 @@ non-default options that potentially present additional security risks. ACLs restrict access, for example any management token grants access to execute arbitrary code on the cluster. +* **Verify Server Hostname Used Alone.** From version 0.5.1 to 1.4.0 we documented that + `verify_server_hostname` being `true` _implied_ `verify_outgoing` however due + to a bug this was not the case so setting _only_ `verify_server_hostname` + results in plaintext communciation between client and server. See + [CVE-2018-19653](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19653) + for more details. This is fixed in 1.4.1. + ## Threat Model The following are parts of the Consul threat model:
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-4qvx-qq5w-695pghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-19653ghsaADVISORY
- github.com/hashicorp/consul/commit/b64e8b262f80397eab4f39c6ae7e14683cb9f55cghsaWEB
- github.com/hashicorp/consul/pull/5069ghsax_refsource_MISCWEB
- groups.google.com/forum/ghsaWEB
- groups.google.com/forum/mitrex_refsource_MISC
News mentions
0No linked articles in our index yet.