CVE-2026-41852
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Framework is the foundational application framework for the Java platform, providing dependency injection, data access, web frameworks, and many supporting libraries. One of those libraries is the Spring Expression Language (SpEL), a runtime expression language that can navigate object graphs, read and write properties, and invoke methods. SpEL is used throughout Spring (for example in @Value annotations, Spring Security expression-based access rules, and Spring Data query derivation) and is also exposed directly to applications that choose to evaluate expressions at runtime. SpEL evaluation is governed by an EvaluationContext, and applications that process expressions influenced by untrusted input are expected to use a restricted context such as SimpleEvaluationContext, which is designed to permit data binding (property and index access) while disallowing arbitrary method invocation, type references, and bean references.
A low-severity vulnerability (CVE-2026-41852) has been identified in the SpEL property-access machinery. When SpEL resolves a property read against a target object, ReflectivePropertyAccessor searches for a matching accessor method using JavaBean and record naming conventions (getX(), isX(), or the record-style x()). The pre-fix resolution logic accepts any zero-argument method whose name matches, without checking its return type, so a zero-argument method that returns void (and may perform side effects) is selected as a getter and then invoked. Because this happens during ordinary property navigation, it occurs even within restricted, read-only evaluation contexts that were intended to forbid method invocation. An application that evaluates attacker-influenced SpEL expressions can therefore be coerced into invoking unintended zero-argument methods on objects reachable from the expression root, escaping the boundary that the restricted context was supposed to enforce.
Per OWASP, access control enforces policy such that users cannot act outside of their intended permissions, and failures typically lead to unauthorized information disclosure, modification, or destruction of data, or performing a business function outside the user's limits. Treating a void, side-effecting method as a readable property lets an expression cross the boundary that the restricted evaluation context was meant to enforce, invoking application logic that the context's policy was specifically configured to disallow.
The CVSS v3.1 base score for this vulnerability is 3.7 (Low) with vector AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L. The attack vector is Network because the affected applications evaluate user-influenced SpEL over the network, attack complexity is High because exploitation depends on the application evaluating untrusted expressions and on a side-effecting zero-argument method existing whose name matches a referenced property, no privileges or user interaction are required, scope is Unchanged, and the only measurable impact is Low to availability from invoking an unintended zero-argument method. There is no direct confidentiality or integrity impact, because the invoked accessor returns void and yields no value back to the expression.
This issue affects Spring Framework >=4.3.0 <=4.3.30, >=5.3.0 <=5.3.48, >=6.1.0 <=6.1.27, >=6.2.0 <=6.2.18, and >=7.0.0 <=7.0.7.
Details
Module Info
- Product: Spring Framework
- Affected packages: spring-expression
- Affected versions: >=4.3.0 <=4.3.30, >=5.3.0 <=5.3.48, >=6.1.0 <=6.1.27, >=6.2.0 <=6.2.18, >=7.0.0 <=7.0.7
- GitHub repository: https://github.com/spring-projects/spring-framework
- Published packages: https://central.sonatype.com/artifact/org.springframework/spring-expression
- Package manager: Maven
- Fixed in:
- NES for Spring Framework 4.3.x, 5.3.x, 6.1.x
- Spring Framework 7.0.8, 6.2.19 (OSS)
Vulnerability Info
The vulnerability is in ReflectivePropertyAccessor in the spring-expression module, specifically in findGetterForProperty(...), which is reached whenever SpEL reads a property (for example the name in an expression like someObject.name). ReflectivePropertyAccessor is the default property accessor used by both StandardEvaluationContext and the restricted SimpleEvaluationContext (via DataBindingPropertyAccessor), so the behavior applies regardless of whether the application intended to allow method invocation.
findGetterForProperty resolves a candidate accessor by delegating to findMethodForProperty(...), which accepts a method when its name matches the accessor naming pattern, its parameter count is zero, and its return type is permitted. The pre-fix code passed ANY_TYPES (an empty set) as the required return types for the get prefix and for the record-style plain accessor, which short-circuits the return-type check:
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
Method method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"get", clazz, mustBeStatic, 0, ANY_TYPES);
if (method == null) {
method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"is", clazz, mustBeStatic, 0, BOOLEAN_TYPES);
if (method == null) {
// Record-style plain accessor method, e.g. name()
method = findMethodForProperty(new String[] {propertyName},
"", clazz, mustBeStatic, 0, ANY_TYPES);
}
}
return method;
}
The matching predicate inside findMethodForProperty is:
if (isCandidateForProperty(method, clazz) && method.getName().equals(prefix + methodSuffix) &&
method.getParameterCount() == numberOfParams &&
(!mustBeStatic || Modifier.isStatic(method.getModifiers())) &&
(requiredReturnTypes.isEmpty() || requiredReturnTypes.contains(method.getReturnType()))) {
return method;
}
Because requiredReturnTypes is empty for the get and record-style cases, requiredReturnTypes.isEmpty() is true and the method's return type is never examined. A zero-argument method that returns void, for example public void getInvalid(), therefore matches and is subsequently invoked by read() through method.invoke(target). The result is that a SpEL property reference can trigger an arbitrary zero-argument method, including methods with side effects, even inside a restricted context whose entire purpose was to permit data binding while forbidding method invocation.
The fix adds a return-type guard so that a void-returning method is no longer treated as a readable property:
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
String[] methodSuffixes = getPropertyMethodSuffixes(propertyName);
Method method = findMethodForProperty(methodSuffixes, "get", clazz, mustBeStatic, 0, ANY_TYPES);
if (method == null) {
method = findMethodForProperty(methodSuffixes, "is", clazz, mustBeStatic, 0, BOOLEAN_TYPES);
if (method == null) {
// Record-style plain accessor method, for example, name()
method = findMethodForProperty(new String[] {propertyName}, "", clazz, mustBeStatic, 0, ANY_TYPES);
}
}
if (method != null && method.getReturnType() == void.class) {
method = null; // not a valid accessor method
}
return method;
}
With the guard in place, a void zero-argument method is rejected as an accessor and is no longer invoked during a property read. The control flow and the public API of ReflectivePropertyAccessor are otherwise unchanged. The fix is delivered in upstream commit 3d47da9746d54775a282717b539924f9e6e39096 ("Ensure getters have non-void return types in SpEL", gh-36800) on the 6.2.x release branch, with the equivalent change shipped on the 7.0.x, 6.1.x, and 5.3.x release branches in the same June 2026 batch. ReflectivePropertyAccessor has existed since Spring Framework 3.0, and the getter resolution logic has accepted void zero-argument methods for that entire time. The advisory's listed floor of 5.3.0 reflects Spring's currently-supported release lines rather than the point at which the behavior was introduced; older lines, including the lines covered by NES support, are also affected.
Steps To Reproduce
1. Build a target type that exposes a side-effecting zero-argument method whose name matches the accessor pattern but returns void:
public class Account {
public void getResetPin() {
// side effect the application never intended SpEL to trigger
this.pin = generateNewPin();
}
}
2. Evaluate a SpEL expression that references that method as if it were a property, using a restricted context that is supposed to forbid method invocation:
SpelExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Account account = new Account();
// The expression looks like a harmless property read...
parser.parseExpression("resetPin").getValue(context, account);
3. Observe that on an affected version (5.3.x through the pre-fix 7.0.x releases listed above) the getResetPin() method is invoked as a getter, running its side effect, even though SimpleEvaluationContext was configured to allow data binding only and not method invocation.
4. After upgrading to a fixed version (6.2.19, 7.0.8), repeat step 2. The void method is no longer treated as a readable property, so it is not invoked and the property read resolves through normal accessor or field resolution instead.
Mitigation
Only recent versions of Spring Framework receive community support and updates. The 5.3.x and 6.1.x lines are past their open-source support windows, so there is no publicly available OSS fix for those lines.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported version of Spring Framework that contains the fix. The OSS fix ships in Spring Framework 7.0.8 (7.0.x line) and 6.2.19 (6.2.x line).
- As defense in depth on any deployment that evaluates expressions derived from untrusted input, avoid evaluating attacker-influenced SpEL, and where SpEL must be evaluated against untrusted input, keep using a restricted SimpleEvaluationContext and ensure that domain types reachable from the expression root do not expose side-effecting zero-argument methods named like accessors.
- Leverage a commercial support partner like HeroDevs for post-EOL security support through Never-Ending Support (NES) for Spring Framework.
Credits
- This issue was discovered internally by the Spring Framework team.