Introduction
A single call to String.equals() in Spring Boot's DevTools remote access manager has been leaking timing information. An attacker on an adjacent network can use that leak to reconstruct the remote secret one character at a time. With the secret in hand, the attacker can push arbitrary class files through the DevTools live reload mechanism. A subtle cryptographic weakness ends in full remote code execution.
CVE-2026-40972 has a CVSS v3.1 score of 7.5 and affects five Spring Boot release trains, from the legacy 2.7.x line to the current 4.0.x series. Spring Boot holds a dominant position in enterprise Java development, so the blast radius is significant for any organization that has inadvertently left DevTools remote support enabled outside a tightly controlled development environment.
Technical Information
Root Cause: Non-Constant-Time Secret Comparison (CWE-208)
The vulnerability is in the HttpHeaderAccessManager class, in the spring-boot-devtools module under org.springframework.boot.devtools.remote.server. This class controls access to the remote DevTools endpoint. It checks a secret sent in an HTTP header against the expected value set by the spring.devtools.remote.secret property.
The original implementation stored the expected secret as a String and compared it to the incoming header value with Java's standard String.equals() method. This is the classic timing oracle pattern described by CWE-208 (Observable Timing Discrepancy). String.equals() short-circuits, returning false as soon as it reaches the first mismatched character. A request whose secret matches the first N characters of the expected value therefore takes measurably longer to reject than a request that differs at position 0.
Attack Flow
The attack proceeds in four steps:
-
Prerequisite: The target Spring Boot application has DevTools remote support enabled, which means the
spring.devtools.remote.secretproperty is set. The attacker must be on the same network (adjacent network access, per the CVSS vector AV:A). -
Timing oracle probing: The attacker sends repeated HTTP requests to the DevTools remote endpoint, changing the secret header value one character at a time. From statistical measurements of the response times, the attacker finds the character at each position that produces a slightly longer comparison, which indicates a match.
-
Secret reconstruction: Repeating this for every position yields the full secret. Network jitter adds noise (reflected in the AC:H rating), but a patient attacker with enough samples can separate the signal from the noise. On a low-latency local network, the attack becomes considerably more practical.
-
Class upload and code execution: The attacker uses the recovered secret to authenticate to the DevTools remote endpoint as a legitimate IDE client. The DevTools protocol lets clients upload changed classes, and the server-side live reload mechanism processes them and loads them into the running application. The attacker uploads a malicious class and gets remote code execution.
CVSS Breakdown
The full CVSS v3.1 vector is AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H, which breaks down as:
| Metric | Value | Practical Meaning |
|---|---|---|
| Attack Vector | Adjacent (A) | Attacker must be on the same network as the target application |
| Attack Complexity | High (H) | Timing attacks require precise measurements and favorable network conditions |
| Privileges Required | None (N) | No prior authentication is needed to initiate the timing attack |
| User Interaction | None (N) | The exploit runs entirely without victim participation |
| Impact (C, I, A) | High (H) | Complete compromise of confidentiality, integrity, and availability via RCE |
The high attack complexity is the main thing keeping this below a critical rating. On a quiet local network segment, though, the timing signal can be quite clear.
Patch Information
The Spring Boot team fixed CVE-2026-40972 in a patch authored by Andy Wilkinson and committed on April 23, 2026 (commit 4b0862cc). The commit message states the intent directly: "Use constant-time comparison for remote DevTools secret."
The patch changes one file, HttpHeaderAccessManager.java, with 7 additions and 3 deletions, and it goes straight at the root cause:
+import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; - private final String expectedSecret; + private final byte[] expectedSecret; public HttpHeaderAccessManager(String headerName, String expectedSecret) { ... - this.expectedSecret = expectedSecret; + this.expectedSecret = expectedSecret.getBytes(StandardCharsets.UTF_8); } @Override public boolean isAllowed(ServerHttpRequest request) { String providedSecret = request.getHeaders().getFirst(this.headerName); - return this.expectedSecret.equals(providedSecret); + return (providedSecret != null) + && MessageDigest.isEqual(providedSecret.getBytes(StandardCharsets.UTF_8), this.expectedSecret); }
The patch makes two changes:
-
Storage format change: The class now stores the expected secret as a
byte[](converted viaStandardCharsets.UTF_8) instead of aString. The constant-time comparison API needs bytes, so this change comes first. -
Constant-time comparison:
MessageDigest.isEqual()replaces the oldString.equals()call. This method, in thejava.securitypackage, is designed for comparing cryptographic values. It always walks the full length of both byte arrays, no matter where they differ, so the comparison time does not depend on the secret's content. The patch also adds a null check (providedSecret != null) as a guard.String.equals()handled null safely by returningfalse, but callinggetBytes()on a null reference would throw aNullPointerException.
The fix was originally tracked as issue #50169 (milestone 3.5.14) and forward-ported to the 4.0.x branch as issue #50176 (milestone 4.0.6).
Fixed Versions
| Affected Version Range | Fixed Version | Availability |
|---|---|---|
| 4.0.0 to 4.0.5 | 4.0.6 | OSS |
| 3.5.0 to 3.5.13 | 3.5.14 | OSS |
| 3.4.0 to 3.4.15 | 3.4.16 | Enterprise Support Only |
| 3.3.0 to 3.3.18 | 3.3.19 | Enterprise Support Only |
| 2.7.0 to 2.7.32 | 2.7.33 | Enterprise Support Only |
The two OSS releases, 4.0.6 and 3.5.14, both list "Remote DevTools performs comparison incorrectly" in their release notes. The older supported branches received the same fix, but those releases are available only through Spring Enterprise Support.
The vendor states that no further mitigation is necessary once the patch is applied. Where you cannot patch right away, disable DevTools remote support entirely, and especially in production, where it should never be enabled in the first place.
Affected Systems and Versions
The vulnerability affects any Spring Boot application with DevTools remote support enabled (that is, the spring.devtools.remote.secret property is set) in these version ranges:
- Spring Boot 4.0.0 through 4.0.5 (fixed in 4.0.6)
- Spring Boot 3.5.0 through 3.5.13 (fixed in 3.5.14)
- Spring Boot 3.4.0 through 3.4.15 (fixed in 3.4.16)
- Spring Boot 3.3.0 through 3.3.18 (fixed in 3.3.19)
- Spring Boot 2.7.0 through 2.7.32 (fixed in 2.7.33)
According to the vendor advisory, versions the vendor no longer supports are also affected. Organizations running unsupported versions must upgrade to a supported release train.
The vulnerable component is the remote DevTools server-side endpoint (HttpHeaderAccessManager in spring-boot-devtools). Applications that neither set spring.devtools.remote.secret nor include DevTools in their deployed artifacts are not affected.
Vendor Security History
The April 23, 2026 Spring Boot release bundled fixes for nine distinct CVEs, which points to an active period of security review. Notable fixes in that release, alongside CVE-2026-40972, include:
| CVE ID | Severity | Description |
|---|---|---|
| CVE-2026-40976 | Critical | Default security filter chain has no authorization rule with Actuator but without Health |
| CVE-2026-40972 | High | DevTools remote secret comparison is vulnerable to timing attacks |
| CVE-2026-40973 | High | Predictable temp directory accepted without ownership verification |
| CVE-2026-40974 | Medium | Cassandra SSL auto configuration disables TLS hostname verification |
Because the fixes shipped together, organizations could address all of them in a single maintenance window. Organizations that rely on open source releases should note that the vendor restricts fixes for the older branches (3.4.x, 3.3.x, 2.7.x) to Enterprise Support Only. Without a commercial support agreement, staying secure on those branches effectively requires a major version upgrade.
References
- NVD: CVE-2026-40972
- CVE Record: CVE-2026-40972
- Spring Security Advisory: CVE-2026-40972
- Spring Blog: Spring Boot 3.5.14 Available Now
- GitHub Release: Spring Boot v3.5.14
- GitHub Release: Spring Boot v4.0.6
- GitHub Issue #50169: Fix for 3.5.14
- GitHub Issue #50176: Fix for 4.0.6
- GitHub Commit 4b0862cc: Use constant-time comparison for remote DevTools secret
- Spring Boot DevTools Documentation
- Heise: VMware Tanzu Spring Boot Attackers Can Access Endpoints
- SecurityOnline: Spring Boot Vulnerability CVE-2026-40976
- Spring Boot Project Page



