CVE-2026-47863
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Reactor Core is the non-blocking Reactive Streams foundation of Project Reactor for the JVM. It provides the Flux and Mono reactive types and the operators built on them, and libraries such as Reactor Netty and Spring WebFlux depend on it. The same repository publishes reactor-test, reactor-tools and reactor-core-micrometer, the Micrometer metrics and observation integration, which follows its own version line: reactor-core-micrometer 1.2.x ships alongside Reactor Core 3.7.x.
A denial of service vulnerability (CVE-2026-47863) has been identified in the Flux.bufferTimeout operator of io.projectreactor:reactor-core when fair backpressure is enabled, which allows attackers who can influence the timing of upstream item delivery to make the stream hang permanently. Items that arrive while a buffer is being flushed can be left in the buffer with no timeout scheduled, so the pipeline stops emitting and processing elements.
Per OWASP: The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed.
This issue affects multiple versions of Reactor Core.
Details
Module Info
- Product: Reactor Core
- Affected packages:
io.projectreactor:reactor-core - Affected versions: >=3.5.7 <=3.7.19, >=3.8.0 <=3.8.6
- GitHub repository: https://github.com/reactor/reactor-core
- Published packages: https://central.sonatype.com/artifact/io.projectreactor/reactor-core
- Package manager: Maven
- Fixed in:
- OSS Reactor Core 3.8.7
- NES for Project Reactor v3.7.22
Vulnerability Info
This High-severity vulnerability is found in the io.projectreactor:reactor-core package in multiple versions of Reactor Core. It affects applications that call Flux.bufferTimeout(maxSize, maxTime, fairBackpressure) with fairBackpressure set to true, which is handled by BufferTimeoutWithBackpressureSubscriber in FluxBufferTimeout.
The subscriber tracks how many items sit in the current buffer as an index in its packed state field, and it schedules the buffer timeout from onNext only when the index goes from zero to one, that is, when a new buffer starts:
previousState = forceAddWork(this, state -> incrementIndex(state, 1));
if (getIndex(previousState) == 0) {
// fire timer, new buffer starts
try {
Disposable disposable =
timer.schedule(this::bufferTimedOut, timeSpan, unit);
currentTimeoutTask.update(disposable);
} catch (RejectedExecutionException e) {
// ...
}
}
When drain decides to flush, it first cancels the pending timeout, emits buffers, may request more items from upstream, and only then subtracts the number of consumed items from the index:
if (shouldFlush) {
currentTimeoutTask.update(null);
for (; ; ) {
int consumedNow = flush();
// ...
}
}
// ...
if (consumed > 0) {
int toDecrement = -consumed;
currentState = forceUpdate(this, state -> resetTimeout(incrementIndex(state, toDecrement)));
previousState = resetTimeout(incrementIndex(previousState, toDecrement));
}
If upstream delivers items after the flush loop has drained the queue but before this index update runs, for example from a concurrent onNext or synchronously inside the requestMore call, those onNext calls see a non-zero index and do not schedule a timer. After the decrement the index is still greater than zero, so the residual items remain buffered, but the timer cancelled at the start of the flush is never rescheduled. Unless enough further items arrive to fill a whole batch, nothing triggers another flush even though the downstream has outstanding demand, and the stream hangs permanently. A party that controls or can shape the rate at which upstream items arrive, such as a message producer feeding the pipeline, can widen this window and stall the consumer, exhausting the application's ability to process data.
Mitigation
Only recent versions of Reactor Core are community-supported. Older release lines are End-of-Life and will not receive community updates addressing this issue. For more information, see here.
Users of the affected components should apply one of the following mitigations:
- Upgrade Reactor Core to a currently supported release containing the fix.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
Credits
- Sage Pierce (finder)