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); } }
