This is an automated email from the ASF dual-hosted git repository.
mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new a7c6cc2584 Fixed: ControlFilter's FreeMarker-interpolation guard was
unreachable due to fail-open security check (OFBIZ-13492) (#1641)
a7c6cc2584 is described below
commit a7c6cc258404340cd3cfef22bbe67acfea7bbcaa
Author: Mridul Pathak <[email protected]>
AuthorDate: Fri Aug 14 21:06:00 2026 +0530
Fixed: ControlFilter's FreeMarker-interpolation guard was unreachable due
to fail-open security check (OFBIZ-13492) (#1641)
LoginWorker.hasBasePermission() returned true whenever the request-scoped
"security" attribute was unresolved, which was effectively always the case
since ControlFilter runs before ContextFilter (the attribute's source) in
nearly every webapp's filter-mapping order. This made the
SSTI/Freemarker-interpolation guard added for OFBIZ-12594/OFBIZ-12602
unreachable across the framework, for any request. hasBasePermission() now
falls back to the Security instance cached on the ServletContex [...]
---
.../src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java | 7 ++++++-
.../java/org/apache/ofbiz/webapp/control/ControlFilterTests.java | 3 +++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
index 7e92561aad..92ffb1c1be 100644
---
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
+++
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
@@ -1429,9 +1429,14 @@ public final class LoginWorker {
}
public static boolean hasBasePermission(GenericValue userLogin,
HttpServletRequest request) {
+ ServletContext context = request.getServletContext();
Security security = (Security) request.getAttribute("security");
+ if (security == null) {
+ // ContextFilter may not have run yet for this request (e.g. when
ControlFilter is mapped
+ // before ContextFilter); the same Security instance is already
cached on the ServletContext.
+ security = (Security) context.getAttribute("security");
+ }
if (security != null) {
- ServletContext context = request.getServletContext();
String serverId = (String) context.getAttribute("_serverId");
// get a context path from the request, if it is empty then assume
it is the root mount point
String contextPath = request.getContextPath();
diff --git
a/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/ControlFilterTests.java
b/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/ControlFilterTests.java
index baae0b4636..eb626d679b 100644
---
a/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/ControlFilterTests.java
+++
b/framework/webapp/src/test/java/org/apache/ofbiz/webapp/control/ControlFilterTests.java
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@@ -52,6 +53,8 @@ public final class ControlFilterTests {
req = mock(HttpServletRequest.class);
when(req.getSession()).thenReturn(session);
when(req.getContextPath()).thenReturn("");
+ // A real HttpServletRequest always has a ServletContext;
LoginWorker.hasBasePermission() relies on this.
+ when(req.getServletContext()).thenReturn(mock(ServletContext.class));
resp = mock(HttpServletResponse.class);
next = mock(FilterChain.class);
System.setProperty("ControlFilterTests",
"bypassPreventsStreamExploitation");