Introduction
A misplaced conditional check in Spring Boot's default security auto configuration silently disables all authorization rules for Actuator endpoints, letting any unauthenticated user pull environment secrets, heap dumps, and configuration properties with a single HTTP request. The flaw, tracked as CVE-2026-40976 with a CVSS 3.1 score of 9.1, affects Spring Boot versions 4.0.0 through 4.0.5 and was patched in the 4.0.6 release on April 23, 2026.
The vulnerability is particularly subtle because it only manifests under a specific but realistic dependency combination: a servlet based web application that relies on the default security filter chain, includes spring-boot-actuator-autoconfigure, and does not include the newer spring-boot-health module. This configuration commonly appears in custom Boot starters, slimmed down container images, or applications that intentionally exclude health endpoints to avoid conflicts.
Technical Information
Root Cause
CVE-2026-40976 is classified as CWE-862 (Missing Authorization). The vulnerability exists at the intersection of Spring Boot 4.0's modular dependency restructuring and its autoconfigured security defaults.
In Spring Boot 4.0, the health endpoint support was extracted from spring-boot-actuator-autoconfigure into a dedicated spring-boot-health module. The default web security configuration in ManagementWebSecurityAutoConfiguration.java used a ClassUtils.isPresent(...) check to determine whether the HealthEndpoint class existed on the classpath. The intent was straightforward: conditionally grant unauthenticated access (permitAll()) only to the health endpoint, while locking down everything else with anyRequest().authenticated().
The critical flaw was in where that conditional check was placed. In the vulnerable code, the entire authorizeHttpRequests block was nested inside the isPresent guard:
if (ClassUtils.isPresent("org.springframework.boot.health.actuate.endpoint.HealthEndpoint", getClass().getClassLoader())) { http.authorizeHttpRequests((requests) -> { requests.requestMatchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll(); requests.anyRequest().authenticated(); }); }
When spring-boot-health was not on the classpath (meaning the HealthEndpoint class was absent), the entire authorization configuration was silently skipped. No rules at all. The default filter chain was registered without any authorization rule covering the Actuator path, leaving every exposed endpoint reachable anonymously.
Exploitation Conditions
For an application to be exploitable, all of the following conditions must be true simultaneously:
| Condition | Description |
|---|---|
| Application Type | Must be a servlet based web application |
| Security Configuration | Must have no Spring Security configuration of its own and rely entirely on the default web security filter chain |
| Actuator Dependency | The classpath must include spring-boot-actuator-autoconfigure |
| Health Dependency | The classpath must NOT include spring-boot-health |
If any single condition is false, the application is not vulnerable.
Attack Flow
An attacker targeting a vulnerable application would follow a straightforward path:
-
Reconnaissance: The attacker identifies a Spring Boot application (often via response headers or error page formatting) and probes the
/actuatorbase path. On a vulnerable instance, this returns a JSON document listing all available Actuator endpoints without requiring any authentication. -
Secret Exfiltration via
/actuator/env: The attacker issues a GET request to/actuator/env, which returns the full applicationEnvironmentincluding resolved property values such as database passwords, API keys, and JWT signing keys. A single request is sufficient for full credential compromise. -
Heap Dump Capture via
/actuator/heapdump: The attacker requests/actuator/heapdump, which triggers a full JVM heap dump. This binary file contains live object state, in memory credentials, and active session tokens. Offline analysis of this dump can reveal secrets that are not present in environment properties. -
Log Manipulation via
/actuator/loggers: The attacker can POST to/actuator/loggersto modify logging levels at runtime, either suppressing security audit logs to cover their tracks or enabling verbose logging to capture additional sensitive data flowing through the application. -
Architecture Mapping via
/actuator/configprops: The attacker retrieves/actuator/configpropsto obtain a complete view of all configuration properties, revealing application architecture, integration wiring, and downstream service endpoints that can be targeted next.
Impact Summary
| Endpoint | Exposed Data | Business Impact |
|---|---|---|
/actuator/env | Database passwords, API keys, JWT signing keys | Full credential compromise and secret exfiltration |
/actuator/heapdump | Live JVM heap with in memory credentials and session tokens | Deep data exposure enabling offline analysis |
/actuator/configprops | All configuration properties | Reveals application architecture and integration details |
/actuator/loggers | Logger configuration (read/write) | Attackers can suppress security logs or enable verbose capture |
The exposure of the environment and heap dump endpoints alone is typically sufficient for an attacker to escalate from anonymous network access to full credential compromise in a single request.
Patch Information
The Spring team addressed CVE-2026-40976 in Spring Boot 4.0.6, released on April 23, 2026. The fix was authored by Andy Wilkinson and committed under SHA 874f6294b91da18367b8b5ab7b2fad3fa23cfba6, directly closing GitHub issue #50188. The fix was also forward ported to the 4.1.x line via issue #50190 (milestone 4.1.0-RC1).
The Servlet Fix
The fix in ManagementWebSecurityAutoConfiguration.java restructures the nesting so the authorization lambda is always applied, and only the health specific permitAll() matcher is conditional:
- if (ClassUtils.isPresent("org.springframework.boot.health.actuate.endpoint.HealthEndpoint", - getClass().getClassLoader())) { - http.authorizeHttpRequests((requests) -> { - requests.requestMatchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll(); - requests.anyRequest().authenticated(); - }); - } + http.authorizeHttpRequests((requests) -> { + if (ClassUtils.isPresent("org.springframework.boot.health.actuate.endpoint.HealthEndpoint", + getClass().getClassLoader())) { + requests.requestMatchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll(); + } + requests.anyRequest().authenticated(); + });
This is a deceptively simple but critically important change: by pulling requests.anyRequest().authenticated() outside the isPresent check, every request is now guaranteed to require authentication regardless of whether the health module is available.
The Reactive Fix
The reactive WebFlux counterpart in ReactiveManagementWebSecurityAutoConfiguration.java had the opposite problem: it did not have any ClassUtils.isPresent guard, meaning it unconditionally tried to call healthMatcher() and additionalHealthPathsMatcher(). The fix wraps just the health specific permit rules inside the presence check, while ensuring anyExchange().authenticated() always applies:
http.authorizeExchange((exchanges) -> { - exchanges.matchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll(); + if (ClassUtils.isPresent("org.springframework.boot.health.actuate.endpoint.HealthEndpoint", + getClass().getClassLoader())) { + exchanges.matchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll(); + } exchanges.anyExchange().authenticated(); });
New Tests
The commit adds a dedicated test method securesEverythingElseWhenHealthIsAbsent() in both the servlet and reactive test suites. This test uses @ClassPathExclusions(packages = "org.springframework.boot.health.actuate.endpoint") to simulate the exact vulnerable configuration and confirms that all endpoints now correctly return 401 Unauthorized. Existing tests were also updated so that the HealthContributorAutoConfiguration, HealthContributorRegistryAutoConfiguration, and HealthEndpointAutoConfiguration classes are explicitly added only in tests that actually exercise health endpoint behavior.
The total change footprint is modest (121 additions and 52 deletions across 4 files) but the security impact is dramatic: it closes a full authorization bypass that left all endpoints unauthenticated under a specific but realistic dependency combination.
Affected Systems and Versions
The vulnerability affects Spring Boot versions 4.0.0 through 4.0.5.
To be vulnerable, an application must meet all four of the following conditions:
- It is a servlet based web application.
- It has no Spring Security configuration of its own and relies entirely on the default web security filter chain.
- Its classpath includes
spring-boot-actuator-autoconfigure. - Its classpath does not include
spring-boot-health.
Applications using Spring Boot versions prior to 4.0.0 are not affected, as the modular split of the health endpoint into a separate module was introduced in the 4.0 line. Applications running Spring Boot 4.0.6 or later, or 4.1.0-RC1 or later, contain the fix.
Vendor Security History
The Spring Boot 4.0.6 release that patches CVE-2026-40976 also addresses three other vulnerabilities discovered in the same version range:
| CVE ID | Vulnerability |
|---|---|
| CVE-2026-40970 | Elasticsearch auto configuration TLS hostname verification disablement |
| CVE-2026-40972 | DevTools remote secret comparison timing attacks |
| CVE-2026-40975 | Random value property source using weak PRNG |
| CVE-2026-40976 | Default security filter chain missing authorization rule |
The bundling of four security fixes in a single release indicates an active security maintenance cycle. The Spring team disclosed the vulnerability and shipped the patch on the same day (April 23, 2026), demonstrating a coordinated disclosure and rapid response process.
References
- NVD: CVE-2026-40976
- CVE Record: CVE-2026-40976
- Spring Security Advisory: CVE-2026-40976
- Spring Boot 4.0.6 Release Announcement
- Spring Boot 4.0.6 Release on GitHub
- GitHub Issue #50188
- Fix Commit 874f6294b91da18367b8b5ab7b2fad3fa23cfba6
- HeroDevs: Spring Boot 4.0 Actuator Authorization Bypass Analysis
- Snyk Vulnerability Database: SNYK-JAVA-ORGSPRINGFRAMEWORKBOOT-16191774
- Spring Boot Actuator Endpoints Documentation



