← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:111351 · Disclosed 2018-07-26

Hashicorp Consul Web UI and API access

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is leaving a side door cracked open, not discovering a new hole in the wall

Tenable plugin 111351 is not a software flaw with a fixed version; it is a configuration exposure finding for HashiCorp Consul. The risky pattern is: the Consul HTTP/UI listener is bound off-loopback via client_addr, the optional Web UI is enabled, and unauthenticated requests inherit permissions from either acl.tokens.default or the built-in anonymous token. HashiCorp documents that client_addr defaults to 127.0.0.1, the UI is not enabled by default for non-dev agents, and ACLs are what secure the API/UI/CLI.

Tenable's HIGH / 8.8 overstates reality for most enterprises because the attack path depends on multiple admin choices that are all non-default and deployment-specific: reachable network exposure, permissive token behavior, and in the worst case additional dangerous settings like enable_script_checks. If those prerequisites are all true on an internet-facing node, the risk climbs fast; but as a fleet-wide patching priority this behaves like a context-heavy hardening issue, not a universally exploitable RCE.

"This is a risky Consul hardening mistake, not a generic 8.8 emergency across the fleet."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Reach the Consul HTTP surface with curl

The attacker first needs TCP reachability to the Consul API/UI, typically port 8500 over HTTP or 8501 over HTTPS. This only exists when operators bind client_addr to a non-loopback address or otherwise publish the service through a proxy, load balancer, or Kubernetes service.
Conditions required:
  • Consul is installed and running
  • client_addr or equivalent exposure is non-loopback
  • Network path exists from attacker to the Consul listener
Where this breaks in practice:
  • HashiCorp documents the default client_addr as 127.0.0.1
  • Many enterprise deployments keep Consul on management or cluster-only networks
  • Firewalls, security groups, or service meshes often block direct access
Detection/coverage: Excellent coverage for listener discovery by Nessus/Nmap and simple HTTP probes; weak at proving the listener is reachable from untrusted zones without path-aware testing.
STEP 02

Inherit permissions through the default or anonymous token

If the attacker sends API requests without a token, Consul will use the configured default ACL token, or the built-in anonymous token if no default token exists. This is the decisive branch: if those effective permissions are restrictive, the finding collapses into mere exposure; if they are permissive, the attacker gets unauthenticated read or write capability.
Conditions required:
  • ACLs are enabled or token behavior is otherwise active
  • Unauthenticated requests map to a token with meaningful permissions
Where this breaks in practice:
  • A correctly configured anonymous token with default_policy = deny blocks useful unauthenticated access
  • The blast radius is constrained by the policy attached to the effective token
  • Tenable does not prove the token policy is actually dangerous on every flagged host
Detection/coverage: Config review and authenticated checks can confirm acl.tokens.default; passive network scanners usually cannot determine the attached policy safely.
STEP 03

Enumerate topology and service data via the API/UI

With readable permissions, the attacker can use curl or the Consul UI to query nodes, services, health checks, and possibly key/value data depending on policy. In a real environment that can leak internal hostnames, addresses, service names, and trust relationships that materially help later movement.
Conditions required:
  • Effective unauthenticated token has read access to catalog, health, or KV endpoints
Where this breaks in practice:
  • Many hardened deployments separate read from write and keep KV secrets elsewhere
  • Read-only exposure is damaging but usually not immediate host takeover
  • Some API endpoints still require stronger privileges than basic catalog discovery
Detection/coverage: Web logs, reverse proxy logs, and Consul audit/logging can show anonymous GETs; most vuln scanners only prove endpoint presence.
STEP 04

Modify service state or weaponize checks with curl/consul

If the inherited permissions include service:write or related agent privileges, an attacker may register or alter services and health checks. That becomes materially worse only if operators also enabled dangerous options such as enable_script_checks or remote exec-related capabilities, which HashiCorp explicitly warns can introduce remote execution risk when the API is exposed.
Conditions required:
  • Effective unauthenticated token includes write permissions
  • The target agent accepts the relevant registration endpoints
  • For code execution scenarios, script checks or remote exec features are enabled
Where this breaks in practice:
  • Service registration write access is not implied by mere UI exposure
  • enable_script_checks is not on by default
  • disable_remote_exec changed to secure-by-default behavior in newer Consul releases
Detection/coverage: Good opportunities for detection in Consul audit/admin logs, config drift tooling, and SIEM alerts on PUT /v1/agent/service/register or new check definitions.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo CVE and not listed in CISA KEV; this is a misconfiguration exposure pattern rather than a tracked vulnerability campaign.
PoC availabilityNo exploit is needed for the base condition; curl against the Consul API is sufficient if the listener is exposed and the effective unauthenticated token is permissive. HashiCorp's own docs show the relevant API paths.
EPSSN/A because this finding has no mapped CVE.
KEV statusNot applicable / not listed; there is no CVE record to track in KEV.
Vendor score baselineTenable assigns CVSS 8.8 with CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H, but that assumes attacker reachability and high-impact permissions that are not inherent to every flagged Consul node.
Affected scopePotentially any Consul version/configuration where the HTTP/UI listener is exposed beyond loopback and unauthenticated requests inherit meaningful ACL rights. This is configuration-dependent, not version-bound.
Fixed versionNone. There is no patched Consul release for this finding; the remedy is configuration hardening: loopback-only or tightly filtered exposure, restrictive anonymous/default token behavior, ACLs, and TLS.
Default behavior that mattersHashiCorp says client_addr defaults to 127.0.0.1 and the Web UI is not enabled by default for non-dev agents. Those defaults are major downward pressure on severity.
Exposure/scanning realityConsul commonly uses port 8500 for API/UI, and internet-scanning ecosystems index that port. Exposure is easy to find when operators publish it, but enterprise reachability is usually limited to internal management networks.
Disclosure / reportingTenable plugin published 2018-07-26; HashiCorp's support article discussing this scanner finding was updated 2025-01-25.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (4.8/10)

The decisive factor is compounded prerequisite friction: this requires non-default network exposure and useful unauthenticated token permissions before it becomes more than a hardening smell. The reachable population is much narrower than the vendor CVSS suggests, and the blast radius is bounded by the effective ACL policy rather than automatic full host compromise.

HIGH This is a configuration issue, not a patchable product CVE
MEDIUM Most flagged hosts do not automatically imply dangerous write or RCE-capable permissions
MEDIUM A truly exposed internet-facing Consul node with permissive tokens would merit a higher case-by-case priority

Why this verdict

  • Downward pressure: requires reachable Consul API/UI. If the listener is left at the documented default 127.0.0.1, the attack chain dies immediately.
  • Downward pressure: requires permissive effective token behavior. Unauthenticated requests only matter if acl.tokens.default or anonymous has useful rights; a deny-by-default anonymous token turns this into noise.
  • Downward pressure: host takeover is not intrinsic. Tenable hints at service registration and remote access, but that escalated outcome generally needs extra risky features like enable_script_checks or remote exec-related capabilities.
  • Upward pressure: if exposed, the intel value is real. Even read-only catalog/KV visibility can materially aid lateral movement by mapping services, nodes, health, and trust edges.
  • Upward pressure: Consul is high-value control-plane tech. Bad permissions here can let an attacker manipulate discovery and traffic decisions, so you should not ignore confirmed unsafe instances.

Why not higher?

This is not a universal unauthenticated RCE and not even a universal unauthorized read. It depends on a stack of non-default conditions: off-loopback binding, network path, permissive token semantics, and possibly additional dangerous features for execution impact.

Why not lower?

A confirmed exposed Consul API with inherited read or write permissions is not harmless. Because Consul is a service-discovery/control-plane component, even partial anonymous access can expose topology or let an attacker poison service state in ways that matter operationally.

05 · Compensating Control

What to do — in priority order.

  1. Bind Consul back to loopback where possible — Set client_addr to loopback or remove the override so the documented default applies. This is the cleanest risk kill-switch and, for a MEDIUM verdict, there is no mitigation SLA — go straight to the 365-day remediation window, but confirmed externally reachable cases should be corrected much sooner as operational hardening.
  2. Strip permissions from unauthenticated paths — Ensure unauthenticated requests fall to a tightly restricted anonymous token and avoid assigning broad rights to acl.tokens.default. This limits exposure even when the API must remain reachable for operational reasons; complete within the same remediation cycle.
  3. Require TLS and trusted network paths — Use TLS for API access and restrict ingress with host firewall rules, security groups, or cluster-only service exposure. This reduces opportunistic discovery and credential leakage while you normalize Consul configs across the fleet.
  4. Keep script-based execution paths off — Verify enable_script_checks is disabled unless there is a documented exception, prefer enable_local_script_checks when needed, and keep remote exec disabled. This prevents the finding from turning into a much nastier execution path.
  5. Alert on anonymous API use — Log and alert on requests lacking X-Consul-Token or bearer auth, plus PUT operations to service/check registration endpoints. This gives you immediate detection value even if the configuration cannot be changed in one maintenance window.
What doesn't work
  • A generic EDR on the host does not solve the base exposure; it may catch a later script-execution stage, but it won't stop topology leakage or service-catalog tampering via the API.
  • Turning on the Web UI login experience alone does not help if unauthenticated API requests still inherit a permissive default or anonymous token.
  • Relying on 'internal only' network assumptions is weak; if the attacker already has a foothold on a workstation, VPN segment, or peered VPC, this becomes reachable post-initial-access.
06 · Verification

Crowdsourced verification payload.

Run this on the target Consul host as root or with enough privileges to read Consul config files and inspect listening sockets. Example: sudo bash ./check_consul_exposure.sh /etc/consul.d; it checks whether Consul is bound off-loopback and whether unauthenticated reads succeed against the local API.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_consul_exposure.sh
# Exit codes:
#   0 = PATCHED (not vulnerable based on current checks)
#   1 = VULNERABLE
#   2 = UNKNOWN

set -u
CONFIG_DIR="${1:-/etc/consul.d}"
API_PORT="8500"
HTTPS_PORT="8501"
status="UNKNOWN"
reason=""

have_cmd() { command -v "$1" >/dev/null 2>&1; }

json_get_http_code() {
  local url="$1"
  curl -ksS -o /tmp/consul_check_body.$$ -w "%{http_code}" "$url" 2>/dev/null || echo "000"
}

cleanup() {
  rm -f /tmp/consul_check_body.$$ 2>/dev/null || true
}
trap cleanup EXIT

if ! have_cmd curl; then
  echo "UNKNOWN - curl not found"
  exit 2
fi

# 1) Check listening addresses for Consul on 8500/8501.
listen_non_loopback=0
if have_cmd ss; then
  if ss -lntp 2>/dev/null | grep -E ':(8500|8501)\b' | grep -vqE '127\.0\.0\.1:|\[::1\]:'; then
    listen_non_loopback=1
  fi
elif have_cmd netstat; then
  if netstat -lntp 2>/dev/null | grep -E ':(8500|8501)\b' | grep -vqE '127\.0\.0\.1:|::1:'; then
    listen_non_loopback=1
  fi
else
  echo "UNKNOWN - neither ss nor netstat found"
  exit 2
fi

# 2) Query unauthenticated local endpoints.
# If HTTP is disabled locally, try HTTPS.
code_catalog="$(json_get_http_code "http://127.0.0.1:${API_PORT}/v1/catalog/services")"
if [[ "$code_catalog" == "000" ]]; then
  code_catalog="$(json_get_http_code "https://127.0.0.1:${HTTPS_PORT}/v1/catalog/services")"
fi

code_self="$(json_get_http_code "http://127.0.0.1:${API_PORT}/v1/agent/self")"
if [[ "$code_self" == "000" ]]; then
  code_self="$(json_get_http_code "https://127.0.0.1:${HTTPS_PORT}/v1/agent/self")"
fi

# 3) Optional config hints.
ui_enabled="unknown"
client_addr_external="unknown"
default_token_present="unknown"
script_checks_enabled="unknown"

if [[ -d "$CONFIG_DIR" ]]; then
  if grep -RqsE 'ui_config\s*\{[^}]*enabled\s*=\s*true|^\s*-ui\b|^\s*ui\s*=\s*true' "$CONFIG_DIR" 2>/dev/null; then
    ui_enabled="true"
  else
    ui_enabled="false"
  fi

  if grep -RqsE 'client_addr\s*=\s*"(0\.0\.0\.0|[^1][^"]*|{{.*}})"' "$CONFIG_DIR" 2>/dev/null; then
    client_addr_external="true"
  else
    client_addr_external="false"
  fi

  if grep -RqsE 'tokens\s*\{[^}]*default\s*=' "$CONFIG_DIR" 2>/dev/null; then
    default_token_present="true"
  else
    default_token_present="false"
  fi

  if grep -RqsE 'enable_script_checks\s*=\s*true' "$CONFIG_DIR" 2>/dev/null; then
    script_checks_enabled="true"
  else
    script_checks_enabled="false"
  fi
fi

# 4) Decision logic.
if [[ "$listen_non_loopback" -eq 1 && ( "$code_catalog" == "200" || "$code_self" == "200" ) ]]; then
  status="VULNERABLE"
  reason="Consul listens off-loopback and unauthenticated API reads succeeded"
elif [[ "$listen_non_loopback" -eq 0 ]]; then
  status="PATCHED"
  reason="Consul listener appears loopback-only"
elif [[ "$listen_non_loopback" -eq 1 && ( "$code_catalog" == "403" || "$code_self" == "403" ) ]]; then
  status="PATCHED"
  reason="Consul is reachable locally but unauthenticated requests are denied; exposure remains a hardening concern if network-published"
else
  status="UNKNOWN"
  reason="Could not conclusively verify listener exposure and unauthenticated access"
fi

echo "${status} - ${reason} | ui_enabled=${ui_enabled} client_addr_external=${client_addr_external} default_token_present=${default_token_present} script_checks_enabled=${script_checks_enabled} http_catalog=${code_catalog} http_self=${code_self}"

case "$status" in
  VULNERABLE) exit 1 ;;
  PATCHED) exit 0 ;;
  *) exit 2 ;;
esac
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: treat this as a configuration validation campaign, not a blanket emergency patch event. For the reassessed MEDIUM verdict there is no noisgate mitigation SLA — go straight to the 365-day remediation window; use that window to normalize Consul so client_addr is loopback-only unless there is a documented need, unauthenticated requests inherit no useful rights, and risky execution features remain off. If you confirm any instance is reachable from untrusted networks *and* anonymous/default-token reads or writes work, do not wait for the general schedule: fix the exposure immediately and complete the permanent configuration correction inside the noisgate remediation SLA of ≤ 365 days.

Sources

  1. Tenable Nessus Plugin 111351
  2. HashiCorp Help Center: Consul Web UI and API is Accessible Remotely if not Configured Properly
  3. HashiCorp Consul UI documentation
  4. HashiCorp Consul security architecture
  5. HashiCorp HTTP API structure and authentication
  6. HashiCorp ACL token documentation
  7. HashiCorp default token and anonymous token relationship
  8. HashiCorp health checks and script-check security warning
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.