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

asf-gitbox-commits pushed a commit to branch 
write-filtered-personalization-contents
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 70acde153b21c24fcc1e017caef23e12148dfe55
Author: Serge Huber <[email protected]>
AuthorDate: Tue Sep 8 21:01:08 2026 +0200

    Keep personalization fallback when mixed contents include a script value.
    
    Add an integration test that posts a mixed personalizations payload and 
expects the safe variant.
---
 .../org/apache/unomi/itests/ContextServletIT.java  | 24 ++++++++++++++++
 .../mvel-payload-personalization-mixed.json        | 32 ++++++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java 
b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
index 36ce3393d..05cfcd90d 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
@@ -928,6 +928,30 @@ public class ContextServletIT extends BaseIT {
                 exists -> exists == Boolean.FALSE, DEFAULT_TRYING_TIMEOUT, 
DEFAULT_SHOULDBETRUE_TRIES);
     }
 
+    @Test
+    public void testPersonalizationDropsScriptContentAndKeepsFallback() throws 
Exception {
+        File vulnFile = new File("target/vuln-file-personalization-mixed.txt");
+        if (vulnFile.exists()) {
+            vulnFile.delete();
+        }
+        String vulnFileCanonicalPath = 
vulnFile.getCanonicalPath().replace("\\", "\\\\");
+
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("VULN_FILE_PATH", vulnFileCanonicalPath);
+        HttpPost request = new HttpPost(getFullUrl(CONTEXT_URL));
+        request.setEntity(new StringEntity(
+                
getValidatedBundleJSON("security/mvel-payload-personalization-mixed.json", 
parameters),
+                ContentType.APPLICATION_JSON));
+        RequestResponse response = executeContextJSONRequest(request, 
TEST_SESSION_ID);
+
+        assertEquals("Invalid response code", 200, response.getStatusCode());
+        List<String> variants = 
response.getContextResponse().getPersonalizations().get("mixed-sanitize");
+        assertNotNull(variants);
+        assertEquals(Collections.singletonList("safe-fallback"), variants);
+        shouldBeTrueUntilEnd("Vulnerability successfully executed ! File 
created at " + vulnFileCanonicalPath, vulnFile::exists,
+                exists -> exists == Boolean.FALSE, DEFAULT_TRYING_TIMEOUT, 
DEFAULT_SHOULDBETRUE_TRIES);
+    }
+
     @Test
     public void testPersonalization() throws Exception {
 
diff --git 
a/itests/src/test/resources/security/mvel-payload-personalization-mixed.json 
b/itests/src/test/resources/security/mvel-payload-personalization-mixed.json
new file mode 100644
index 000000000..4d11b1ae0
--- /dev/null
+++ b/itests/src/test/resources/security/mvel-payload-personalization-mixed.json
@@ -0,0 +1,32 @@
+{
+  "personalizations": [
+    {
+      "id": "mixed-sanitize",
+      "strategy": "matching-first",
+      "strategyOptions": {
+        "fallback": "safe-fallback"
+      },
+      "contents": [
+        {
+          "id": "injected",
+          "filters": [
+            {
+              "condition": {
+                "type": "profilePropertyCondition",
+                "parameterValues": {
+                  "propertyName": "firstName",
+                  "comparisonOperator": "equals",
+                  "propertyValue": "script::Runtime r = Runtime.getRuntime(); 
r.exec(\"touch ###VULN_FILE_PATH###\");"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "id": "safe-fallback"
+        }
+      ]
+    }
+  ],
+  "sessionId": "demo-session-id"
+}

Reply via email to