This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts-site.git


The following commit(s) were added to refs/heads/main by this push:
     new 224e0c2d29 WW-5846 docs: describe exemptedPaths matching and 
cross-site form posts (#371)
224e0c2d29 is described below

commit 224e0c2d293c1d43e40b376cc2fd86f6ea7f985f
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Nov 7 18:56:31 2026 +0100

    WW-5846 docs: describe exemptedPaths matching and cross-site form posts 
(#371)
    
    The Fetch Metadata, COOP and COEP interceptor pages now state that
    exemptedPaths entries are compared exactly with the request path inside the
    application (servlet path plus path info, extension included) since 7.5.0 /
    6.13.0, and that an entry equal to the context path no longer disables the
    interceptor app-wide.
    
    The Fetch Metadata page also documents the policy as implemented, notes the
    interceptor is in defaultStack, and explains that cross-site POST 
navigations
    (SAML/OIDC form_post, payment returns) are rejected since 7.5.0 / 6.13.0
    (WW-5753, WW-5754), with exemptedPaths and disabled as the opt-outs.
    
    Examples move exemptedPaths to a stack-level configuration.
    
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 source/core-developers/coep-interceptor.md         | 30 ++++++++----
 source/core-developers/coop-interceptor.md         | 30 ++++++++----
 .../core-developers/fetch-metadata-interceptor.md  | 57 +++++++++++++++++++---
 3 files changed, 91 insertions(+), 26 deletions(-)

diff --git a/source/core-developers/coep-interceptor.md 
b/source/core-developers/coep-interceptor.md
index 00606ac159..68cb5e7bd1 100644
--- a/source/core-developers/coep-interceptor.md
+++ b/source/core-developers/coep-interceptor.md
@@ -25,21 +25,31 @@ COEP is now supported by all major browsers. [More 
information about COEP](https
 
 ## Parameters
 
-- `exemptedPaths` - Set of opt out endpoints that are meant to serve 
cross-site traffic. Paths should contain leading
-   slashes and must be relative. This field is empty by default.
+- `exemptedPaths` - Comma-separated list of request paths the COEP header is 
not sent on. Each entry is compared exactly
+  with the path of the request inside the web application: the servlet path 
plus the path info, without the context path
+  and without the query string. Include the action extension, e.g. 
`/embed/widget.action`; if an action is reachable
+  with several extensions, list each form. This field is empty by default.
 - `enforcingMode` - Boolean variable allowing the user to let COEP operate in 
`enforcing`, which blocks both resource 
    and reports violations, or `report-only` mode, which only reports 
violations. Default value for field is `false`.
 - `disabled` - Boolean variable disabling and enabling COEP. Default value for 
field is `false`.
 
+Before Struts 7.5.0 and 6.13.0 `exemptedPaths` was compared with the context 
path of the application, so an entry
+naming a request path had no effect and an entry equal to the context path 
disabled the interceptor for the whole
+application. Use `disabled` if you relied on the latter.
+{:.alert .alert-warning}
+
 ## Examples
 
 ```xml
-<action  name="someAction" class="com.examples.SomeAction">
-    <interceptor-ref name="defaultStack">
-        <param name="coep.exemptedPaths">/path1,/path2,/path3</param>
-        <param name="coep.enforcingMode">false</param>
-        <param name="coep.disabled">false</param>
-    </interceptor-ref>
-    <result name="success">good_result.ftl</result>
-</action>
+<package name="default" extends="struts-default">
+    <interceptors>
+        <interceptor-stack name="appDefaultStack">
+            <interceptor-ref name="defaultStack">
+                <param name="coep.exemptedPaths">/embed/widget.action</param>
+                <param name="coep.enforcingMode">false</param>
+            </interceptor-ref>
+        </interceptor-stack>
+    </interceptors>
+    <default-interceptor-ref name="appDefaultStack"/>
+</package>
 ```
diff --git a/source/core-developers/coop-interceptor.md 
b/source/core-developers/coop-interceptor.md
index 212621faee..b68398dd57 100644
--- a/source/core-developers/coop-interceptor.md
+++ b/source/core-developers/coop-interceptor.md
@@ -36,19 +36,31 @@ COOP is now supported by all major browsers. [More 
information about COOP](https
 
 ## Parameters
 
-- `exemptedPaths` - Set of opt out endpoints that are meant to serve 
cross-site traffic. Paths should contain leading 
-  slashes and must be relative. This field is empty by default.
+- `exemptedPaths` - Comma-separated list of request paths the COOP header is 
not sent on. Each entry is compared exactly
+  with the path of the request inside the web application: the servlet path 
plus the path info, without the context path
+  and without the query string. Include the action extension, e.g. 
`/popup/callback.action`; if an action is reachable
+  with several extensions, list each form. This field is empty by default.
 - `mode` - The policy mode COOP should follow. Available modes are 
`same-origin`, `same-origin-allow-popups`, 
   `unsafe-none`. Default mode is `same-origin`.
+- `disabled` - Set to `true` to skip the interceptor for an action. Default 
value is `false`.
+
+Before Struts 7.5.0 and 6.13.0 `exemptedPaths` was compared with the context 
path of the application, so an entry
+naming a request path had no effect and an entry equal to the context path 
disabled the interceptor for the whole
+application. Use `disabled` if you relied on the latter.
+{:.alert .alert-warning}
 
 ## Examples
 
 ```xml
-<action  name="someAction" class="com.examples.SomeAction">
-    <interceptor-ref name="defaultStack">
-        <param name="coop.exemptedPaths">/path1,/path2,/path3</param>
-        <param name="coop.mode">same-origin</param>
-    </interceptor-ref>
-    <result name="success">good_result.ftl</result>
-</action>
+<package name="default" extends="struts-default">
+    <interceptors>
+        <interceptor-stack name="appDefaultStack">
+            <interceptor-ref name="defaultStack">
+                <param name="coop.exemptedPaths">/popup/callback.action</param>
+                <param name="coop.mode">same-origin</param>
+            </interceptor-ref>
+        </interceptor-stack>
+    </interceptors>
+    <default-interceptor-ref name="appDefaultStack"/>
+</package>
 ```
diff --git a/source/core-developers/fetch-metadata-interceptor.md 
b/source/core-developers/fetch-metadata-interceptor.md
index e55013a3eb..2cc3bd40a9 100644
--- a/source/core-developers/fetch-metadata-interceptor.md
+++ b/source/core-developers/fetch-metadata-interceptor.md
@@ -14,32 +14,75 @@ An interceptor that implements Fetch Metadata on incoming 
requests used to prote
 information leaks. Uses a default Resource Isolation Policy to 
programmatically reject cross-origin requests.
 
 A Resource Isolation Policy is a strong defense in-depth mechanism that 
prevents the resources on a server from being 
-requested by external websites. This policy can be enabled either for all 
endpoints of the application and  endpoints 
+requested by external websites. The interceptor is part of the `defaultStack` 
and is enabled by default; endpoints
 that are meant to be loaded in a cross-site context can be exempted from the 
policy.
 
 The browser provides information about the context of an HTTP request in a set 
of `Sec-Fetch-*` headers. This allows 
 the server processing the request to make decisions on whether the request 
should be accepted or rejected based 
 on the preferred resource isolation policy. Struts provides a default 
_Resource Isolation Policy_ that rejects 
-_cross-origin_ requests that aren't top level navigations.
+_cross-site_ requests that aren't simple top level navigations:
 
 ```
-Sec-Fetch-Site == 'cross-site' AND (Sec-Fetch-Mode != 
'navigate'/'nested-navigate' OR method NOT IN [GET, HEAD])
+Sec-Fetch-Site == 'cross-site' AND (Sec-Fetch-Mode != 'navigate' OR method NOT 
IN [GET, HEAD] OR Sec-Fetch-Dest IN [object, embed])
 ```
 
+Requests without a `Sec-Fetch-Site` header and `same-origin`, `same-site` and 
`none` requests are always accepted.
+
 Refer to [Implementing a Resource Isolation 
Policy](https://web.dev/fetch-metadata/#implementing-a-resource-isolation-policy)
 
 for further information on implementing effective Resource Isolation Policies. 
Fetch Metadata is supported in all major browsers.
 
+## Cross-site form posts
+
+Since Struts 7.5.0 and 6.13.0 cross-site `POST` navigations are rejected with 
`403`.
+{:.alert .alert-info}
+
+Flows where another site posts the user's browser back to your application are 
affected, for example:
+
+- a SAML assertion consumer service or an OpenID Connect `form_post` response,
+- a payment gateway returning the user to the shop.
+
+Exempt the endpoints receiving these requests, either by path with 
`exemptedPaths` or per action with the `disabled`
+parameter, see the examples below.
+
 ## Parameters
 
-- `exemptedPaths` - Set of opt out endpoints that are meant to serve 
cross-site traffic. Paths should contain leading 
-   slashes and must be relative. This field is empty by default.
+- `exemptedPaths` - Comma-separated list of request paths the policy is not 
applied to. Each entry is compared exactly
+  with the path of the request inside the web application: the servlet path 
plus the path info, without the context path
+  and without the query string. Include the action extension, e.g. 
`/saml/acs.action`; if an action is reachable with
+  several extensions, list each form. This field is empty by default.
+- `disabled` - Set to `true` to skip the interceptor for an action. Default 
value is `false`.
+
+Before Struts 7.5.0 and 6.13.0 `exemptedPaths` was compared with the context 
path of the application, so an entry
+naming a request path had no effect and an entry equal to the context path 
disabled the interceptor for the whole
+application. Use `disabled` if you relied on the latter.
+{:.alert .alert-warning}
+
+When `struts.mapper.action.prefix.enabled` is set to `true` (it is `false` by 
default), a request to an exempted path
+can use the `action:` parameter prefix to execute another action in the same 
namespace.
 
 ## Examples
 
+Exempt selected paths for every action using the stack:
+
+```xml
+<package name="default" extends="struts-default">
+    <interceptors>
+        <interceptor-stack name="appDefaultStack">
+            <interceptor-ref name="defaultStack">
+                <param 
name="fetchMetadata.exemptedPaths">/saml/acs.action,/payment/return.action</param>
+            </interceptor-ref>
+        </interceptor-stack>
+    </interceptors>
+    <default-interceptor-ref name="appDefaultStack"/>
+</package>
+```
+
+Disable the interceptor for a single action:
+
 ```xml
-<action  name="someAction" class="com.examples.SomeAction">
+<action name="acs" class="com.examples.SamlAssertionConsumerAction">
     <interceptor-ref name="defaultStack">
-            <param 
name="fetchMetadata.exemptedPaths">/path1,/path2,/path3</param>
+        <param name="fetchMetadata.disabled">true</param>
     </interceptor-ref>
     <result name="success">good_result.ftl</result>
 </action>

Reply via email to