The Exploit
An unauthenticated remote attacker can bypass the W3C Baggage specification 64 KiB size limit by sending an oversized baggage HTTP header, triggering denial of service or memory pressure on the Keycloak server.
GET /auth/admin/realms HTTP/2
Host: target-keycloak-host
baggage: <PAYLOAD_OF_OVER_64_KILOBYTES_OF_PADDING>
When the request is processed, the server will consume excessive memory attempting to extract and propagate the baggage entry before the size limit check is applied. In high-throughput scenarios, repeated exploitation can cause the JVM to run out of heap space, leading to service unavailability.
What the Patch Did
Before (vulnerable — the size-limited wrapper did not exist):
// No SizeLimitedBaggagePropagatorCustomizer existed.
// The W3CBaggagePropagator was used directly with no size enforcement.
After (fixed):
@Singleton
public class SizeLimitedBaggagePropagatorCustomizer implements TextMapPropagatorCustomizer {
@Override
public TextMapPropagator customize(Context context) {
TextMapPropagator propagator = context.propagator();
if (propagator instanceof W3CBaggagePropagator) {
return new SizeLimitedBaggagePropagator(propagator);
}
return propagator;
}
}
The patch introduces a TextMapPropagatorCustomizer that replaces the vanilla W3CBaggagePropagator with a SizeLimitedBaggagePropagator wrapper. This is an input size validation control added at the OpenTelemetry context propagation boundary. The wrapper enforces the W3C Baggage specification's 64 KiB limit on the combined baggage header value before delegating extraction to the underlying propagator.
Root Cause
The vulnerability (CWE-770: Allocation of Resources Without Limits or Throttling) lies in the absence of any size enforcement when Keycloak processes the baggage HTTP header via the OpenTelemetry SDK (versions <= 1.61.0). The dataflow is: attacker sends an HTTP request with a baggage header containing arbitrarily large data -> the Quarkus HTTP layer passes all headers to the OpenTelemetry TextMapPropagator -> the W3CBaggagePropagator iterates over baggage entries without checking cumulative header size -> each entry is parsed into heap-allocated objects. Because no trust boundary crosses between the untrusted HTTP header input and the internal propagation context, an attacker can send a payload that forces the server to allocate memory proportional to payload size, leading to denial of service. The baggage header parameter name is the sole attacker-controlled input.
Why It Works
The single load-bearing line in the fix is the instanceof W3CBaggagePropagator check followed by wrapping it in SizeLimitedBaggagePropagator. If removed, the customizer would be a no-op and the vanilla (unbounded) propagator would remain in use, leaving the bug fully exploitable. The engineer added the guard clause (if (!(propagator instanceof ...)) return propagator;) for defensive programming: if future Quarkus versions replace the W3CBaggagePropagator with a different class, the customizer will not break the propagation chain by wrapping an incompatible propagator. The @Singleton annotation ensures only one instance is created, preventing a different class of resource leak. The @Deprecated removal in AdminRoles.java is an unrelated cleanup.
Hardening Checklist
- Enforce size limits on all untrusted HTTP headers at the proxy or servlet filter layer. For OpenTelemetry baggage specifically, validate that the total
baggageheader value does not exceed 64 KiB before it reaches any parsing logic. TheHttpServletRequest.getHeader("baggage")method returns the raw value — measure its length before any content processing. - Use a
javax.servlet.Filterto reject oversize headers globally. Register a filter with@WebFilter("/*")that callsresponse.sendError(413, "Header Too Large")if any single header exceeds 8 KiB or total header size exceeds 16 KiB, as recommended by the HTTP/1.1 specification (RFC 7230 Section 3.2.5). - Apply resource limits via the OpenTelemetry SDK configuration. Upgrade to OpenTelemetry SDK 1.62.0+ which includes built-in baggage size limits. In the interim, set
-Dotel.baggage.maxSizeBytes=65536if the SDK version supports it. - Enable JVM memory monitoring and alerting. Configure
-XX:+HeapDumpOnOutOfMemoryErrorand set heap usage alerts at 80% in your monitoring system (Prometheus/Grafana, New Relic) to catch resource exhaustion attacks early. - Unit test the propagator customizer. Write a test that sends a
baggageheader of 65537 bytes and asserts that the server returns HTTP 413 or that the baggage is silently discarded, not parsed.
References
- https://nvd.nist.gov/vuln/detail/CVE-2026-45292
- https://github.com/open-telemetry/opentelemetry-java/releases/tag/v1.62.0 (upstream fix)
- https://github.com/keycloak/keycloak/issues/49570 (vendor tracking issue)