high · 7.5CVE-2026-81516Sep 17, 2026

CVE-2026-81516: Steeltoe.Discovery.Consul Malformed 'secure' Metadata DoS

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A service registered in Consul with a non-boolean 'secure' metadata value (like 'yes' or '1') crashes Steeltoe's discovery client mid-enumeration, making every affected service unreachable until the…

PackageSteeltoe.Discovery.Consul
Ecosystemnuget
Affected>= 4.0.0, <= 4.2.0
Fixed in4.3.0

The problem

Steeltoe's ConsulDiscoveryClient calls bool.Parse() on the 'secure' metadata field of every registered service instance. bool.Parse() in .NET throws a FormatException for any input that is not exactly 'true' or 'false' (case-insensitive).

Because the exception is unhandled at the per-instance level, it propagates up and aborts construction of the entire instance list for the service. When GetAllInstancesAsync is used, one poisoned instance in any single service kills enumeration across all services, causing a full discovery outage.

Proof of concept

A working proof-of-concept for CVE-2026-81516 in Steeltoe.Discovery.Consul, with the exact payload below.

http
# Register a service in Consul with a non-boolean 'secure' metadata value.
# Any value other than 'true' or 'false' triggers the FormatException in Steeltoe.
# Examples of malformed values: 'yes', 'no', '1', '0', 'on', 'enabled'

PUT http://consul-agent:8500/v1/agent/service/register
Content-Type: application/json

{
  "Name": "my-service",
  "ID": "my-service-poison-1",
  "Address": "10.0.0.1",
  "Port": 8080,
  "Meta": {
    "secure": "yes"
  }
}

# After registration, any Steeltoe app calling:
#   await consulDiscoveryClient.GetInstancesAsync("my-service");
#   await consulDiscoveryClient.GetAllInstancesAsync();
# will throw and return an empty/aborted instance list.

The root cause (CWE-755) is that bool.Parse() is the wrong tool for untrusted, external data. It is a strict converter that throws on anything outside 'True'/'False', with no way to supply a fallback. The fix in commit 028569c replaced it with bool.TryParse(), which returns false on unrecognized input instead of throwing, and also added null-safety guards for missing metadata keys.

Because Consul's service registration API is typically open to any service in the mesh, the attack requires no special privileges beyond the ability to register a service. In mixed-platform environments, non-.NET clients that use common shorthand values like 'yes' or '1' can trigger this unintentionally.

The fix

Upgrade Steeltoe.Discovery.Consul to 4.3.0 or later (commit 028569c4f4f0e9e393e3c22a4fa5d07987dd8673). The fix replaces bool.Parse() with bool.TryParse() so malformed 'secure' values default to false instead of throwing. If an immediate upgrade is not possible, audit the Consul catalog for service registrations whose 'secure' metadata value is not exactly 'true' or 'false', and restrict write access to the Consul service registration API to trusted services only.

Reporter not attributed.

References: [1][2][3][4][5]

Related research