CVE-2026-40990

Denial of Service
Affects
Spring Cloud Function
in
Spring
No items found.
Versions
<3.2.16, >=4.0.0 <=4.2.5, >=4.3.0 <=4.3.2, >=5.0.0 <=5.0.1
Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

Spring Cloud Function is a project within the Spring Cloud ecosystem that promotes the implementation of business logic via plain Java functions. It provides a uniform programming model across serverless providers and the ability to run standalone via Spring Boot, and it surfaces a FunctionCatalog that resolves function-definition strings (including pipe-delimited compositions such as upper|reverse) into invokable wrappers at runtime. Behind the catalog, SimpleFunctionRegistry keeps a map of every function-definition string it has resolved so that the next caller asking for the same definition gets the same wrapper instance.

A medium-severity vulnerability (CVE-2026-40990) has been identified in SimpleFunctionRegistry in the spring-cloud-function-context module. The registry's wrapper cache is declared as a bare HashMap with no cap, no eviction policy, and no expiration. Every novel function-definition string the registry resolves becomes a permanent entry that lives for the lifetime of the application context. A caller able to drive the registry's lookup(...) path with a stream of distinct function-definition strings (for example over HTTP via the Spring Cloud Function Web adapter, or via the recursive self-composition pattern tracked separately as CVE-2026-40989) causes the map to grow without bound, exhausts the JVM heap, and takes the application down with OutOfMemoryError.

Per OWASP: "The 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 resources handling vulnerabilities, among others." This CVE is the textbook resource-handling form: an in-memory cache that accepts unbounded distinct keys with no eviction is, by definition, an unbounded memory primitive.

The CVSS v3.1 base score for this vulnerability is 5.4 (Medium) with vector AV:P/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:H. The published vector lists the attack vector as Physical, but the abuse pattern is exercised through any call into FunctionCatalog.lookup(...), so deployments that surface user-controlled function-definition strings over HTTP should treat reachability as broader than AV:P implies.

This issue affects Spring Cloud Function <3.2.16, >=4.0.0 <=4.2.5, >=4.3.0 <=4.3.2, and >=5.0.0 <=5.0.1.

Details

Module Info

  • Product: Spring Cloud Function
  • Affected packages: spring-cloud-function-context
  • Affected versions: <3.2.16, >=4.0.0 <=4.2.5, >=4.3.0 <=4.3.2, >=5.0.0 <=5.0.1
  • GitHub repository
  • Published packages
  • Package manager: Maven
  • Fixed in:
  •   NES for Spring Cloud Function 3.1.x, 3.2.x, 4.1.x, 4.2.x
  •   OSS Spring Cloud Function 4.3.3, 5.0.2

Vulnerability Info

The vulnerability is in SimpleFunctionRegistry in the spring-cloud-function-context module, in the lifetime management of the wrappedFunctionDefinitions cache that the registry keeps for previously-resolved function-definition strings.

In Spring Cloud Function, every function (user-defined beans, the built-in routing function functionRouter, and any composition string the catalog has been asked to resolve) is registered in the catalog as a FunctionInvocationWrapper. When a caller asks the catalog to look up a definition, the registry first checks whether the wrapper for that exact string already exists; if not, it resolves the string (recursively, for compositions), constructs a fresh FunctionInvocationWrapper, and inserts it into the wrapper cache for next time. Pre-fix, the cache is declared as a bare HashMap:

private final Map<String, FunctionInvocationWrapper> wrappedFunctionDefinitions = new HashMap<>();

The cache is populated from inside the lookup/composition path:

this.wrappedFunctionDefinitions.put(composedFunction.functionDefinition, composedFunction);

There is no cap, no eviction policy, and no expiration. Every distinct lookup key, whether a legitimate composition that happens to be unique, a typo, or an adversarial high-entropy function-definition string, produces a permanent entry. Two concrete abuse patterns drive the map to OOM:

  1. A remote caller able to reach the routing layer (over HTTP via spring-cloud-function-web, or any other transport that surfaces user-controlled function-definition strings) sends a stream of unique function-definition values. Even if every value resolves to the same underlying business function, the cache stores one entry per distinct string. Heap grows linearly with request count.
  2. The recursive self-composition pattern from CVE-2026-40989 (functionRouter|functionRouter, when the routing function is itself the target of spring.cloud.function.definition) re-enters the registry on each iteration, allocates a new FunctionInvocationWrapper, and inserts it. Each iteration adds one cache entry; heap exhausts in a small number of self-composed lookups.

Both abuse patterns cross the same primitive: wrappedFunctionDefinitions accepts unbounded distinct keys with no eviction.

The fix replaces the bare HashMap with a self-evicting LinkedHashMap whose eviction policy is governed by removeEldestEntry:

private int wrappedFunctionDefinitionsCacheSize = 1000;

public SimpleFunctionRegistry(ConversionService conversionService, CompositeMessageConverter messageConverter,
        JsonMapper jsonMapper, FunctionProperties functionProperties,
        FunctionInvocationHelper<Message<?>> functionInvocationHelper) {
    // ...
    this.wrappedFunctionDefinitions = new LinkedHashMap<String, FunctionInvocationWrapper>() {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, FunctionInvocationWrapper> eldest) {
            boolean remove = size() > wrappedFunctionDefinitionsCacheSize;
            if (remove) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Removing message channel from cache " + eldest.getKey());
                }
            }
            return remove;
        }
    };
}

Once the cache reaches wrappedFunctionDefinitionsCacheSize (default 1000), each subsequent insertion evicts the oldest entry. The bound is configurable via the private wrappedFunctionDefinitionsCacheSize field (used as a test seam by the upstream regression test, which reflects on it to drop the cap to 10).

The same commit adds value-equality (equals/hashCode) on FunctionInvocationWrapper and a self-composition guard in FunctionInvocationWrapper.andThen(...) that throws IllegalArgumentException when a function is composed with itself; those changes close the related CVE-2026-40989. CVE-2026-40990 is the cache-bound change, and it is sufficient on its own to remove the unbounded-memory primitive: any future bypass smuggling in a new flavor of recursive or otherwise miss-heavy composition lookups is bounded by the 1000-entry cap.

Steps To Reproduce

1. Deploy a Spring Cloud Function Web application on an affected pre-fix version (for example 4.3.2):

 <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-function-web</artifactId>
       <version>4.3.2</version>
   </dependency>
   @SpringBootApplication
   public class Application {
       public static void main(String[] args) {
           SpringApplication.run(Application.class, args);
       }

       @Bean
       public Function<String, String> echo() {
           return value -> value;
       }
   }

2. Drive a function lookup that adds many distinct entries to the wrapper cache. The simplest reproducer uses the Spring Cloud Function FunctionCatalog directly:

 FunctionCatalog catalog = applicationContext.getBean(FunctionCatalog.class);
   for (int i = 0; i < 1_000_000; i++) {
       catalog.lookup("echo|echo|" + i); // each iteration inserts a fresh entry
   }

Equivalently, on a Spring Cloud Function Web deployment that surfaces routing over HTTP, a caller able to set spring.cloud.function.definition (via property, environment, or a spring.cloud.function.definition header where the application accepts it) can repeatedly request distinct composition strings and trigger the same allocation pattern.

3. Watch the JVM heap. Pre-fix, the registry's wrappedFunctionDefinitions map grows linearly with the request count; the JVM eventually throws OutOfMemoryError and the application terminates.

4. After upgrading to a fixed version (4.3.3, 5.0.2, or a HeroDevs NES build for 3.1.x, 3.2.x, 4.1.x, or 4.2.x), the same workload runs steady-state with at most 1000 entries in the cache, and each new lookup evicts the oldest entry rather than growing heap.

Mitigation

Only recent versions of Spring Cloud Function receive community support and updates. Older versions have no publicly available fixes for this vulnerability.

Users of the affected components should apply one of the following mitigations:

  • Upgrade to a currently supported version of Spring Cloud Function. The OSS fix ships in Spring Cloud Function 4.3.3 and 5.0.2.
  • Leverage a commercial support partner like HeroDevs for post-EOL security support through Never-Ending Support (NES) for Spring Cloud Function. The HeroDevs NES builds for 3.1.x, 3.2.x, 4.1.x, and 4.2.x carry the same fix.

As an interim hardening step on a vulnerable deployment, constrain the surface area that allows callers to set spring.cloud.function.definition (or an equivalent header) so that the function-definition strings reaching SimpleFunctionRegistry.lookup(...) come from a small, bounded set. This does not fix the unbounded-cache primitive but caps the cardinality of cache keys an attacker can introduce.

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2026-40990
PROJECT Affected
Spring Cloud Function
Versions Affected
<3.2.16, >=4.0.0 <=4.2.5, >=4.3.0 <=4.3.2, >=5.0.0 <=5.0.1
NES Versions Affected
NES for Spring Cloud Function 3.1.x, 3.2.x, 4.1.x, 4.2.x
Published date
May 12, 2026
≈ Fix date
April 27, 2026
Category
Denial of Service
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for Spring
Rss feed icon
Subscribe via RSS
or

By clicking “submit” I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.