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

jsinovassin pushed a commit to branch 
backport/personalization-filter-writeback-3.0.x
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 517983629c4337e044bf083ef1c289bf7606cbf3
Author: Serge Huber <[email protected]>
AuthorDate: Wed Sep 23 06:18:05 2026 +0200

    Write filtered personalization contents back onto the request (#876)
    
    (cherry picked from commit a51bf3c9ebf4aea42e7dd39d0f5607cefd25d1bd)
---
 .../org/apache/unomi/itests/ContextServletIT.java  | 24 ++++++++++++++++
 .../mvel-payload-personalization-mixed.json        | 32 ++++++++++++++++++++++
 .../unomi/rest/endpoints/ContextJsonEndpoint.java  |  1 +
 3 files changed, 57 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 fa51b228b..1c5a7218e 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
@@ -511,6 +511,30 @@ public class ContextServletIT extends BaseIT {
                 exists -> exists == Boolean.FALSE, DEFAULT_TRYING_TIMEOUT, 
DEFAULT_TRYING_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"
+}
diff --git 
a/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java 
b/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java
index 39eca1220..60752fabd 100644
--- 
a/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java
+++ 
b/rest/src/main/java/org/apache/unomi/rest/endpoints/ContextJsonEndpoint.java
@@ -320,6 +320,7 @@ public class ContextJsonEndpoint {
             List<PersonalizationService.PersonalizedContent> 
personalizedContents = sanitizePersonalizedContentObjects(
                     personalizationRequest.getContents());
             if (personalizedContents != null && 
!personalizedContents.isEmpty()) {
+                personalizationRequest.setContents(personalizedContents);
                 result.add(personalizationRequest);
             }
         }

Reply via email to