CVE-2026-40997
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Web Services (Spring WS) is the Spring portfolio project for building contract-first SOAP web services, providing message dispatching, marshalling, and WS-Security integration on top of the core Spring Framework, including security callback handlers that plug Spring Security into WS-Security processing.
A medium-severity vulnerability (CVE-2026-40997) has been identified in Spring Web Services. Several Spring WS integration paths with Spring Security could surface detailed account state, such as locked or disabled user semantics, to remote SOAP clients through exception messages or callback outcomes, instead of failing with a generic authentication error. A remote client probing the username-token, digest, or X.509 certificate validation paths could distinguish accounts that do not exist from accounts that exist but are locked, disabled, or expired, and the leaked exception text could include the full user details string with the username and its granted authorities. This assists attackers in enumerating valid accounts and inferring their lifecycle state.
Per OWASP, this kind of weakness enables account enumeration: web applications can reveal when a username exists on the system, either as a consequence of mis-configuration or as a design decision, and the resulting list of valid usernames can then be used for brute force and credential stuffing attacks.
This issue affects >=2.4.0 <=2.4.7, >=3.1.0 <=3.1.8, >=4.0.0 <=4.0.18, >=4.1.0 <=4.1.3, and >=5.0.0 <=5.0.1 of Spring Web Services. Versions that are no longer supported are also affected.
Details
Module Info
- Product: Spring Web Services
- Affected packages: spring-ws-security
- Affected versions: >=2.4.0 <=2.4.7, >=3.1.0 <=3.1.8, >=4.0.0 <=4.0.18, >=4.1.0 <=4.1.3, >=5.0.0 <=5.0.1
- GitHub repository: https://github.com/spring-projects/spring-ws
- Published packages: https://central.sonatype.com/artifact/org.springframework.ws/spring-ws-security
- Package manager: Maven
- Fixed in:
- NES for Spring Web Services 2.4.x, 3.1.x, 4.0.x
- Spring Web Services 5.0.2, 4.1.4 (OSS)
Vulnerability Info
The spring-ws-security module ships callback handlers and an authentication provider that connect WS-Security processing to Spring Security user accounts. When an inbound SOAP message carries a UsernameToken, the SpringSecurityPasswordValidationCallbackHandler loads the user through the configured UserDetailsService and, before handing the stored password to the WS-Security runtime for comparison, checks the account's lifecycle state through the SpringSecurityUtils.checkUserValidity helper. In affected versions, that helper threw a distinct exception type for each account state and embedded the full UserDetails object in the exception message:
public static void checkUserValidity(UserDetails user)
throws AccountExpiredException, CredentialsExpiredException, DisabledException, LockedException {
if (!user.isAccountNonLocked()) {
throw new LockedException("Account for user '" + user + "' is locked");
}
if (!user.isEnabled()) {
throw new DisabledException("User '" + user + "' is disabled");
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException("Account for user '" + user + "' has expired");
}
if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException("Credentials for user '" + user + "' have expired");
}
}
Spring Security's User.toString() includes the username, the enabled, locked, and expired flags, and the list of granted authorities, so the message leaked all of that detail. The callback handler let these exceptions propagate out of UsernameToken handling:
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
UserDetails user = loadUserDetails(callback.getIdentifier());
if (user != null) {
SpringSecurityUtils.checkUserValidity(user);
callback.setPassword(user.getPassword());
}
}
As a result, the SOAP security fault raised for a valid but locked or disabled account differed observably from the fault raised for an unknown user or a wrong password, and could carry the account-state wording and authority list to the remote client. The X509AuthenticationProvider used for client certificate authentication had the same shape of problem, letting account-status exception types surface at the SOAP layer instead of a uniform BadCredentialsException.
The remediation makes all of these paths fail generically. SpringSecurityUtils.checkUserValidity is deprecated and now delegates to Spring Security's AccountStatusUserDetailsChecker, which uses standard wording without embedding the user object. SpringSecurityPasswordValidationCallbackHandler accepts an injectable UserDetailsChecker, catches AccountStatusException during UsernameToken handling, and leaves the callback password unset so the WS-Security runtime reports the same generic authentication failure as for an unknown user. X509AuthenticationProvider maps account-status failures to a BadCredentialsException with the generic "Bad credentials" message.
Mitigation
Spring Web Services 5.0.x and 4.1.x receive the fix in the open-source releases 5.0.2 and 4.1.4. The 4.0.x and 3.1.x lines, along with older lines such as 2.x and 1.5.x, are past their open-source support window and have no publicly available fix. Users still running an affected line that no longer receives free updates should not attempt to hand-patch the security callback handlers.
To remediate this issue, affected users have two recommended options:
- Upgrade to a supported, fixed release of Spring Web Services (5.0.2 or 4.1.4).
- Adopt HeroDevs Never-Ending Support (NES) for Spring Web Services, which provides a drop-in compatible build with this vulnerability fixed for release lines that are otherwise End-of-Life, with no code changes required. Learn more about HeroDevs Never-Ending Support for Spring.