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" +}
