Introduction
A predictable temporary directory in Spring Boot's ApplicationTemp class allows a local attacker to hijack the location used for session persistence and other sensitive temporary data, potentially leading to authenticated session theft or arbitrary code execution. For any organization running Spring Boot applications in multi-tenant environments or on shared hosts, this vulnerability quietly turns a common framework convenience into a local privilege escalation path.
Spring Boot is the most widely adopted Java framework for building web applications and microservices. Given its ubiquity across enterprise environments, the blast radius of CVE-2026-40973 is significant even though exploitation requires local access. The CVSS base score of 7.0 (HIGH) reflects the combination of high confidentiality, integrity, and availability impact with the constraint of local access and high attack complexity.
Technical Information
Root Cause: Predictable Directory Names Without Ownership Verification
The vulnerability resides in the ApplicationTemp class, which provides Spring Boot applications with a dedicated temporary directory. According to the Spring Boot API documentation, while different Spring Boot applications receive different temporary locations, restarting a specific application yields the exact same directory location. This deterministic behavior is the first ingredient of the vulnerability.
The second ingredient is the absence of any validation on an existing directory at that path. Prior to the fix, the code used Files.exists(path) to check whether the temporary directory already existed. This call transparently follows symbolic links, meaning an attacker who placed a symlink at the predictable path could redirect the application's temporary storage to an attacker-controlled location without the application noticing.
There was also no ownership verification. If the directory already existed (created by another user), the application would simply use it without checking who owned it.
Attack Flow
The exploitation of CVE-2026-40973 follows a specific sequence:
-
Predict the directory path. The attacker, who has local access to the host, determines the predictable temporary directory path that a target Spring Boot application will use. Because
ApplicationTempgenerates the same path for the same application across restarts, this is straightforward. -
Pre-create or symlink the directory. Before the application starts (or restarts), the attacker either creates a directory at the predicted path under their own user account, or plants a symbolic link pointing to an attacker-controlled directory.
-
Wait for application restart. The application starts and finds the directory (or symlink) already in place. The old code's
Files.exists(path)call follows the symlink and sees a valid directory, so it proceeds without creating a new one. -
Exploit session persistence. If the application has
server.servlet.session.persistentset totrue, session data is written to and read from this compromised directory across restarts. The attacker now has two exploitation options:- Session hijacking: Read the stored session information to impersonate authenticated users.
- Code execution via deserialization: Place a malicious gadget chain in the session data. When the application deserializes this data on restart, it executes arbitrary code under the application's user privileges.
CWE Classification
This vulnerability is classified under CWE-377: Insecure Temporary File, which describes the creation of temporary files in a manner that allows local attackers to interfere with the file's intended use.
Patch Information
The Spring Boot team released the official patch on April 23, 2026, authored and committed by Andy Wilkinson. The fix was originally developed on the 3.5.x branch (issue #50170, commit 5ceb1a2) and then forward-ported to the 4.0.x branch (issue #50178, merge commit 8e013b6). The change modifies a single production file, ApplicationTemp.java, with 57 additions and 4 deletions, plus 25 lines of new tests in ApplicationTempTests.java.
The patch introduces three key defense mechanisms:
1. Symlink-safe existence checks via LinkOption.NOFOLLOW_LINKS
Previously, the code checked for the directory with Files.exists(path), which transparently follows symbolic links. The fix replaces this with:
if (!Files.exists(path, LinkOption.NOFOLLOW_LINKS)) { Files.createDirectory(path, asFileAttributes(fileSystem, DIRECTORY_PERMISSIONS)); }
By using NOFOLLOW_LINKS, the check now detects a symlink as a symlink rather than blindly following it to the target. All subsequent attribute reads also pass LinkOption.NOFOLLOW_LINKS to prevent TOCTOU (time-of-check-to-time-of-use) races.
2. Directory ownership verification
The constructor now captures the running process's identity by creating a temporary file and reading its owner:
private static @Nullable UserPrincipal directoryOwner() { try { Path tempFile = Files.createTempFile("application-temp", "-owner"); UserPrincipal owner = Files.getOwner(tempFile); Files.delete(tempFile); return owner; } catch (UnsupportedOperationException ex) { return null; } catch (IOException ex) { throw new UncheckedIOException(ex); } }
This UserPrincipal is stored in a new directoryOwner field. When an existing directory is found, a new method assertDirectoryOwnership() compares the directory's actual owner against the expected one, failing with an IllegalStateException if they differ. This prevents a local attacker who created the directory under their own UID from having it accepted by the application.
3. Permission and type validation on POSIX systems
On POSIX-capable filesystems, when the directory already exists, the patch reads PosixFileAttributes (without following links) and enforces that:
- The entry is truly a directory (not a symlink, file, or other entity):
Assert.state(attributes.isDirectory(), ...) - Its permissions match the expected owner-only permission set:
Assert.state(DIRECTORY_PERMISSIONS.equals(attributes.permissions()), ...) - Its owner matches the running application's user:
assertDirectoryOwnership(attributes.owner(), path)
On non-POSIX filesystems, ownership is still checked where the OS supports Files.getOwner(), gracefully degrading if unsupported.
The accompanying tests validate that an IllegalStateException is raised both when a symlink is planted at the expected directory location and when the existing directory has incorrect permissions.
Fixed Versions
| Affected Branch | Fixed Version | Availability |
|---|---|---|
| Spring Boot 4.0.x (4.0.0 through 4.0.5) | 4.0.6 | OSS (Maven Central) |
| Spring Boot 3.5.x (3.5.0 through 3.5.13) | 3.5.14 | OSS (Maven Central) |
| Spring Boot 3.4.x (3.4.0 through 3.4.15) | 3.4.16 | Enterprise Support Only |
| Spring Boot 3.3.x (3.3.0 through 3.3.18) | 3.3.19 | Enterprise Support Only |
| Spring Boot 2.7.x (2.7.0 through 2.7.32) | 2.7.33 | Enterprise Support Only |
Organizations on 3.4.x, 3.3.x, or 2.7.x without an enterprise support subscription from VMware Tanzu must migrate to the 3.5.x or 4.0.x open source branches to receive the fix. The vendor states that no further mitigation steps are necessary beyond applying the appropriate version upgrade.
Affected Systems and Versions
The vulnerability affects the following Spring Boot versions:
- Spring Boot 4.0.x: versions 4.0.0 through 4.0.5
- Spring Boot 3.5.x: versions 3.5.0 through 3.5.13
- Spring Boot 3.4.x: versions 3.4.0 through 3.4.15
- Spring Boot 3.3.x: versions 3.3.0 through 3.3.18
- Spring Boot 2.7.x: versions 2.7.0 through 2.7.32
The vendor advisory also notes that versions which are no longer supported are affected as well.
The vulnerability is exploitable when:
- The attacker has local access to the same host as the Spring Boot application.
- The application uses the
ApplicationTempclass for temporary directory management (default behavior). - For the most severe impact (session hijacking and code execution), the Spring Environment property
server.servlet.session.persistentmust be set totrue.
Multi-tenant environments, shared hosting platforms, and containerized deployments where multiple users or processes share a filesystem namespace are at elevated risk.
Vendor Security History
The Spring project maintains a mature security advisory process with a track record of coordinated disclosures and rapid patch availability. A notable prior example is CVE-2022-22965, widely known as Spring4Shell, which involved remote code execution via data binding on JDK 9 and higher. The handling of CVE-2026-40973 demonstrates a continuation of this structured approach, providing clear mitigation guidance and specific version matrices for both open source and commercial users.
The Italy CSIRT has also issued warnings regarding recent Spring security flaws, highlighting CVE-2026-40973 alongside other vulnerabilities and assessing the system impact rating as High.
References
- CVE-2026-40973: Predictable temp directory, Spring Security Advisory
- CVE-2026-40973 Detail, NVD
- Spring Boot 4.0.6 Release
- Spring Boot 3.5.14 Release
- Spring Boot 4.0.6 Available Now, Spring Blog
- GitHub Issue #50170 (3.5.x branch)
- GitHub Issue #50178 (4.0.x branch)
- Patch Commit 8e013b6 (4.0.x)
- Patch Commit 5ceb1a2 (3.5.x)
- ApplicationTemp API Documentation (Spring Boot 4.0.5)
- CVE-2022-22965: Spring Framework RCE via Data Binding on JDK 9+
- CISA Known Exploited Vulnerabilities Catalog Update, April 14 2026
- Italy CSIRT Warns of Spring Security Flaws



