CVE-2026-41710
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Retry is a Java library that provides declarative and programmatic retry support for Spring applications, letting callers automatically re-invoke an operation that has failed transiently. It backs the @Retryable annotation, the RetryTemplate API, and circuit-breaker functionality, and is used both directly and as a transitive dependency across the Spring ecosystem.
A medium-severity vulnerability (CVE-2026-41710) has been identified in Spring Retry's stateful retry support. When stateful retries are enabled, Spring Retry stores per-attempt state in an application-wide retry-context cache (MapRetryContextCache). That cache is backed by a plain HashMap with a hard capacity bound (DEFAULT_CAPACITY = 4096) and no eviction. When the cache key is derived from attacker-controllable request input, an attacker can craft a large number of unique requests that trigger a failure, each of which inserts a new entry into the shared cache. Abandoned failing entries persist until the operation either succeeds or exhausts its retry policy, so they occupy cache slots indefinitely. Once the cache reaches capacity, MapRetryContextCache.put() throws RetryCacheCapacityExceededException and no further entries can be added, denying retry and circuit-breaker state to all subsequent callers, including legitimate ones.
Per OWASP, a Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed; there are many ways to make a service unavailable for legitimate users by manipulating network packets, programming, logical, or resource-handling vulnerabilities, among others. Exhausting the shared retry-context cache with attacker-seeded failing keys is a resource-handling instance of this class: a bounded, non-evicting cache is filled until it can no longer admit new entries.
This issue affects versions 1.3.0 through 1.3.4 and 2.0.0 through 2.0.12 of Spring Retry.
Details
Module Info
- Product: Spring Retry
- Affected packages: spring-retry
- Affected versions: >=1.3.0 <=1.3.4, >=2.0.0 <=2.0.12
- GitHub repository: https://github.com/spring-projects/spring-retry
- Published packages: https://central.sonatype.com/artifact/org.springframework.retry/spring-retry
- Package manager: Maven
- Fixed in:
- NES for Spring Retry
- Spring Retry 2.0.13 (OSS)
Vulnerability Info
The vulnerability is in org.springframework.retry.policy.MapRetryContextCache, the default RetryContextCache implementation used to hold per-key retry state during stateful retries.
An application is exposed when all of the following are true:
- Stateful retries are explicitly enabled, for example @Retryable(stateful = true), a stateful RetryState, or a circuit-breaker configuration.
- The cache key is attacker-controllable, that is, derived from request input.
- The attacker can cause the guarded invocation to fail.
Under those conditions, every unique failing request seeds a new entry in the application-wide cache. Entries are only removed when the corresponding operation succeeds or its retry policy is exhausted, so a flood of distinct, abandoned failing requests fills the cache and never releases the slots.
Prior to the fix, MapRetryContextCache.put() was backed by a plain HashMap and threw when full, with no eviction:
public static final int DEFAULT_CAPACITY = 4096;
private final Map<Object, RetryContext> map = Collections.synchronizedMap(new HashMap<>());
public void put(Object key, RetryContext context) {
if (map.size() >= capacity) {
throw new RetryCacheCapacityExceededException("Retry cache capacity limit breached. "
+ "Do you need to re-consider the implementation of the key generator, "
+ "or the equals and hashCode of the items that failed?");
}
map.put(key, context);
}
Two properties of this implementation make the denial of service possible. First, the map has a hard ceiling and no eviction policy, so once it reaches capacity it stays full and rejects all new keys permanently. Second, regular stateful retries and circuit-breaker state share a single fail-fast cache instance, so exhaustion caused by one path poisons the other. The shared, non-evicting cache is the denial-of-service surface: attacker-seeded entries it can never reclaim block legitimate callers from registering retry state.
Mitigation
The 1.3.x line of Spring Retry is End-of-Life and the affected releases do not receive further OSS security fixes. Older versions have no publicly available fix for this vulnerability outside of the noted releases.
Users of the affected versions should apply one of the following mitigations:
- Upgrade to a currently supported version of Spring Retry. The OSS fix ships in Spring Retry 2.0.13; commercial-support backports are available as 2.0.12.1 and 1.3.5.
- Leverage a commercial support partner like HeroDevs for post-EOL security support through Never-Ending Support (NES) for Spring Retry.
Credits
- No external reporter was credited for this issue.