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

joerghoh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-xss.git


The following commit(s) were added to refs/heads/master by this push:
     new 2991c35  Sanitizer policy reload failure could leave sanitizer in a 
degraded state
2991c35 is described below

commit 2991c35f654814ce216cb3f07078e4dedda07166
Author: Joerg Hoh <[email protected]>
AuthorDate: Mon Sep 14 18:26:10 2026 +0200

    Sanitizer policy reload failure could leave sanitizer in a degraded state
---
 .../org/apache/sling/xss/impl/XSSFilterImpl.java   | 28 +++++++++++++++-------
 .../apache/sling/xss/impl/XSSFilterImplTest.java   | 24 +++++++++++++++++++
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/apache/sling/xss/impl/XSSFilterImpl.java 
b/src/main/java/org/apache/sling/xss/impl/XSSFilterImpl.java
index 9e00c2b..dd31b6d 100644
--- a/src/main/java/org/apache/sling/xss/impl/XSSFilterImpl.java
+++ b/src/main/java/org/apache/sling/xss/impl/XSSFilterImpl.java
@@ -558,16 +558,28 @@ public class XSSFilterImpl implements XSSFilter {
 
     synchronized void updateActivePolicy() {
         final AntiSamyPolicy originalActivePolicy = this.activePolicy;
-        this.activePolicy = withPolicyResource(AntiSamyPolicy::create);
-        // the originalActivePolicy can only be null during the first 
activation
-        if (activePolicy == null && originalActivePolicy == null) {
-            // the content-based policy file is not (yet) available, fall back 
to the embedded policy
-            this.activePolicy = AntiSamyPolicy.createEmbedded();
-            if (activePolicy == null) {
-                throw new IllegalStateException("Cannot load a policy 
handler.");
+        AntiSamyPolicy newActivePolicy = 
withPolicyResource(AntiSamyPolicy::create);
+        if (newActivePolicy == null) {
+            // the content-based policy file is not (or no longer) available 
or failed to load, fall
+            // back to the embedded policy.
+            if (originalActivePolicy != null && 
!originalActivePolicy.isEmbedded()) {
+                logger.error("Unable to load a policy from {}. Falling back to 
the embedded policy file.", policyPath);
+            }
+            newActivePolicy = AntiSamyPolicy.createEmbedded();
+            if (newActivePolicy == null) {
+                if (originalActivePolicy != null) {
+                    logger.error(
+                            "Unable to load the embedded policy file either. 
Keeping the previously active policy from {}.",
+                            originalActivePolicy.getPath());
+                    return;
+                } else {
+                    throw new IllegalStateException(
+                            "Cannot load neither embedded policy nor policy 
file at '" + policyPath + "'");
+                }
             }
         }
-        updatePolicyHandler(activePolicy.getPolicyHandler());
+        this.activePolicy = newActivePolicy;
+        updatePolicyHandler(newActivePolicy.getPolicyHandler());
     }
 
     private <T> T withPolicyResource(Function<Resource, T> mapper) {
diff --git a/src/test/java/org/apache/sling/xss/impl/XSSFilterImplTest.java 
b/src/test/java/org/apache/sling/xss/impl/XSSFilterImplTest.java
index 5791839..640a1d0 100644
--- a/src/test/java/org/apache/sling/xss/impl/XSSFilterImplTest.java
+++ b/src/test/java/org/apache/sling/xss/impl/XSSFilterImplTest.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
+import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.external.URIProvider;
 import org.apache.sling.commons.metrics.Counter;
@@ -159,6 +160,29 @@ public class XSSFilterImplTest {
         testResourceBasedPolicy();
     }
 
+    @Test
+    public void testPolicyRemovalFallsBackToEmbeddedPolicy() throws 
PersistenceException {
+        String policyPath = "/libs/" + XSSFilterImpl.DEFAULT_POLICY_PATH;
+        context.load().binaryFile(getPolicyFileAsStream(), policyPath);
+        // re-register in order to pick up the newly uploaded policy
+        xssFilter = context.registerInjectActivateService(new XSSFilterImpl());
+        assertFalse(xssFilter.getActivePolicy().isEmbedded(), "Expected a 
Resource based policy.");
+
+        Resource policyResource = 
context.resourceResolver().getResource(policyPath);
+        context.resourceResolver().delete(policyResource);
+        context.resourceResolver().commit();
+
+        // simulate the resource change event delivered when the policy 
resource is removed; this
+        // must never leave the filter without a working policy
+        xssFilter.updateActivePolicy();
+
+        XSSFilterImpl.AntiSamyPolicy antiSamyPolicy = 
xssFilter.getActivePolicy();
+        assertTrue(antiSamyPolicy.isEmbedded(), "Expected a fallback to the 
embedded policy.");
+        assertTrue(
+                xssFilter.check(XSSFilter.DEFAULT_CONTEXT, "<p>some text</p>"),
+                "Expected the filter to keep working after the policy resource 
was removed.");
+    }
+
     @Test
     public void testDefaultEmbeddedPolicy() {
         XSSFilterImpl.AntiSamyPolicy antiSamyPolicy = 
xssFilter.getActivePolicy();

Reply via email to