[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[FD] Apache Struts2 Core Cross-Origin Protection Exemption Miskeyed to a Deployment-Wide Path
- To: "fulldisclosure@xxxxxxxxxxxx" <fulldisclosure@xxxxxxxxxxxx>
- Subject: [FD] Apache Struts2 Core Cross-Origin Protection Exemption Miskeyed to a Deployment-Wide Path
- From: Daniel Owens via Fulldisclosure <fulldisclosure@xxxxxxxxxxxx>
- Date: Thu, 29 Oct 2026 13:34:55 +0000
Description
Apache Struts2 Core version 7.4.0 and below's `FetchMetadataInterceptor`,
`CoepInterceptor`, and `CoopInterceptor` each compare their `exemptedPaths`
configuration -- a per-interceptor-reference, administrator-supplied set of
paths intended to exempt specific actions from the corresponding cross-origin
protection -- against `HttpServletRequest.getContextPath()`.
`getContextPath()` is fixed for the entire deployed web application and is
identical on every request regardless of which action or servlet path is being
invoked, so it cannot distinguish one action from another.
Impact
An administrator who configures `exemptedPaths` expecting it to exempt a
specific action or endpoint, instead is configuring a value that can never
match the real, single, deployment-wide context path returned on genuine
traffic, so the per-action exemption never takes effect and the intended
protection remains enforced everywhere, including on the endpoint the
administrator believed was exempted. More importantly, if an administrator's
configured exemption string happens to coincide with the application's actual
context path -- such as if an administrator assumes that the parameter takes a
path-like value and supplies the deployment's own root or an equally-named
segment -- `exemptedPaths.contains(contextPath)` evaluates to `true` on every
single request to the application and Fetch Metadata request filtering, the
Cross-Origin Embedder Policy (COEP) header, and the Cross-Origin Opener Policy
(COOP) header are all silently disabled for the entire deployment (well beyond
the endpoint
that the administrator intended to exempt), disabling the protections that
such code is intended to provide across the entire application.
Examples
Sample Code
All three interceptors, each in `struts2-core`, apply the identical pattern --
a per-action `exemptedPaths` set compared against the deployment-wide
`getContextPath()` rather than against anything that actually varies per action.
```java
private final Set<String> exemptedPaths = new HashSet<>();
private final ResourceIsolationPolicy resourceIsolationPolicy = new
StrutsResourceIsolationPolicy();
@Inject(required = false)
public void setExemptedPaths(String paths) {
this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = context.getServletRequest();
addVaryHeaders(invocation);
String contextPath = request.getContextPath();
// Apply exemptions: paths/endpoints meant to be served cross-origin
if (exemptedPaths.contains(contextPath)) {
return invocation.invoke();
}
```
Code snippet from `struts2-core`'s
core/src/main/java/org/apache/struts2/interceptor/FetchMetadataInterceptor.java,
lines 55-73
```java
@Override
public void beforeResult(ActionInvocation invocation, String resultCode) {
HttpServletRequest req =
invocation.getInvocationContext().getServletRequest();
final String path = req.getContextPath();
if (exemptedPaths.contains(path)) {
```
Snippet from `struts2-core`'s
core/src/main/java/org/apache/struts2/interceptor/CoepInterceptor.java, lines
59-63
```java
@Override
public void beforeResult(ActionInvocation invocation, String resultCode) {
HttpServletRequest request =
invocation.getInvocationContext().getServletRequest();
String path = request.getContextPath();
if (isExempted(path)) {
```
Code from `struts2-core`'s
core/src/main/java/org/apache/struts2/interceptor/CoopInterceptor.java, lines
61-65
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/