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

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


The following commit(s) were added to refs/heads/unomi-3.0.x by this push:
     new 12a7603bc Write filtered personalization contents back onto the 
request (unomi-3.0.x) (#890)
12a7603bc is described below

commit 12a7603bc9a22216303a047971add8c4782ee50f
Author: Jonathan SINOVASSIN-NAIK <[email protected]>
AuthorDate: Wed Oct 14 17:32:28 2026 +0200

    Write filtered personalization contents back onto the request (unomi-3.0.x) 
(#890)
    
    Co-authored-by: Serge Huber <[email protected]>
---
 .../org/apache/unomi/itests/ContextServletIT.java  | 26 ++++++++++++++++++
 .../mvel-payload-personalization-mixed.json        | 32 ++++++++++++++++++++++
 .../unomi/rest/endpoints/ContextJsonEndpoint.java  |  1 +
 3 files changed, 59 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..606598056 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,32 @@ 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));
+        // The payload declares its own sessionId, so the request is sent 
without asserting one:
+        // the two-argument helper checks that the context echoes the id it 
was given.
+        TestUtils.RequestResponse response = 
TestUtils.executeContextJSONRequest(request);
+
+        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_TRYING_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