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

bitstorm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/wicket.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e07eee9be Added JS sanitazing and and fix for PackageResource
4e07eee9be is described below

commit 4e07eee9be9fbc7f426e8a3c2c659d8cde556b97
Author: Andrea Del Bene <[email protected]>
AuthorDate: Thu Apr 30 16:18:19 2026 +0200

    Added JS sanitazing and and fix for PackageResource
---
 .../core/util/string/JavaScriptUtilsTest.java      |  7 +++
 .../wicket/markup/html/PackageResourceTest.java    | 70 +++++++++++++++++++---
 .../wicket/markup/html/link/ExternalLinkTest.java  | 61 +++++++++++++++++++
 .../apache/wicket/markup/html/link/LinkTest.java   | 65 +++++++++++++++++++-
 .../snake_case/TestPageInsideSnakeCasePackage.html | 11 ++++
 .../TestPageInsideSnakeCasePackage.java}           | 32 +---------
 .../apache/wicket/markup/html/snake_case/style.css |  0
 .../wicket/core/util/string/JavaScriptUtils.java   | 20 +++++++
 .../wicket/markup/html/link/ExternalLink.java      |  8 ++-
 .../org/apache/wicket/markup/html/link/Link.java   |  2 +-
 .../wicket/markup/html/link/PopupSettings.java     |  7 ++-
 .../wicket/request/resource/PackageResource.java   | 51 +++++-----------
 .../autocomplete/AbstractAutoCompleteRenderer.java |  3 +-
 .../AbstractAutoCompleteRendererTest.java          | 66 ++++++++++++++++++++
 14 files changed, 323 insertions(+), 80 deletions(-)

diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/core/util/string/JavaScriptUtilsTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/core/util/string/JavaScriptUtilsTest.java
index b849101615..07b5c4ec10 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/core/util/string/JavaScriptUtilsTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/core/util/string/JavaScriptUtilsTest.java
@@ -16,10 +16,12 @@
  */
 package org.apache.wicket.core.util.string;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.apache.wicket.response.StringResponse;
 import org.apache.wicket.util.value.AttributeMap;
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -97,4 +99,9 @@ class JavaScriptUtilsTest
                        JavaScriptUtils.SCRIPT_OPEN_TAG);
                assertEquals("\n/*]]>*/\n</script>\n", 
JavaScriptUtils.SCRIPT_CLOSE_TAG);
        }
+
+       @Test
+       void escapeQuotesAndBackslash(){
+               
assertThat(JavaScriptUtils.escapeQuotesAndBackslash("alert('foo\\tbar')")).isEqualTo("alert(\\'foo\\\\tbar\\')");
+       }
 }
diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/PackageResourceTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/PackageResourceTest.java
index 11bd855db2..0a0c00f4f0 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/PackageResourceTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/PackageResourceTest.java
@@ -16,16 +16,11 @@
  */
 package org.apache.wicket.markup.html;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.util.Locale;
-
 import org.apache.wicket.Application;
 import org.apache.wicket.SharedResources;
+import org.apache.wicket.markup.html.snake_case.TestPageInsideSnakeCasePackage;
 import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.https.HttpPage;
 import org.apache.wicket.request.resource.JavaScriptPackageResource;
 import org.apache.wicket.request.resource.PackageResource;
 import org.apache.wicket.request.resource.PackageResourceReference;
@@ -35,6 +30,12 @@ import org.apache.wicket.util.tester.WicketTestCase;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.*;
+
 /**
  * Tests for package resources.
  * 
@@ -193,4 +194,59 @@ public class PackageResourceTest extends WicketTestCase
                final String contentType = 
tester.getLastResponse().getContentType();
                assertEquals("text/javascript; charset=" + encoding, 
contentType);
        }
+
+       @Test
+       void getResourceStream()
+       {
+               PackageResource resource = new 
PackageResourceReference(PackageResourceTest.class,
+                       "packaged1.txt").getResource();
+               assertThat(resource.getResourceStream()).isNotNull();
+       }
+
+       @Test
+       void dontGetResourceStream()
+       {
+               PackageResource resource = new 
PackageResourceReference(HttpPage.class,
+                       "HttpPage.html").getResource();
+               assertThatThrownBy(resource::getResourceStream).isInstanceOf(
+                       PackageResource.PackageResourceBlockedException.class);
+       }
+
+       @Test
+       void dontGetResourceStreamIfNameHasSuffix()
+       {
+               PackageResource resource = new 
PackageResourceReference(HttpPage.class,
+                       "HttpPage_en.html").getResource();
+               assertThatThrownBy(resource::getResourceStream).isInstanceOf(
+                       PackageResource.PackageResourceBlockedException.class);
+       }
+
+       @Test
+       void getResourceStreamInSnakeCasePackage()
+       {
+               PackageResource resource = new PackageResourceReference(
+                       TestPageInsideSnakeCasePackage.class, 
"style.css").getResource();
+               assertThat(resource.getResourceStream()).isNotNull();
+       }
+
+       @Test
+       void dontGetResourceStreamInSnakeCasePackage()
+       {
+               PackageResource resource = new PackageResourceReference(
+                       TestPageInsideSnakeCasePackage.class,
+                       "TestPageInsideSnakeCasePackage.html").getResource();
+               assertThatThrownBy(resource::getResourceStream).isInstanceOf(
+                       PackageResource.PackageResourceBlockedException.class);
+       }
+
+       @Test
+       void dontGetResourceStreamInSnakeCasePackageIfNameHasSuffix()
+       {
+               PackageResource resource = new PackageResourceReference(
+                       TestPageInsideSnakeCasePackage.class,
+                       "TestPageInsideSnakeCasePackage_en.html").getResource();
+               assertThatThrownBy(resource::getResourceStream).isInstanceOf(
+                       PackageResource.PackageResourceBlockedException.class);
+       }
+
 }
diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
index 99a6612dbb..e28f607f67 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
@@ -16,9 +16,15 @@
  */
 package org.apache.wicket.markup.html.link;
 
+import org.apache.wicket.MockPageWithOneComponent;
+import org.apache.wicket.core.util.string.JavaScriptUtils;
+import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.util.tester.WicketTestCase;
 import org.junit.jupiter.api.Test;
 
+import static org.apache.wicket.MockPageWithOneComponent.COMPONENT_ID;
+import static org.assertj.core.api.Assertions.assertThat;
+
 /**
  * Test ExternalLink (href="...")
  * 
@@ -26,6 +32,61 @@ import org.junit.jupiter.api.Test;
  */
 class ExternalLinkTest extends WicketTestCase
 {
+
+       @Test
+       void allowsJavascriptScheme() throws Exception
+       {
+               String uri = "javascript:alert(1)";
+               MockPageWithOneComponent page = new MockPageWithOneComponent();
+               page.add(new ExternalLink(COMPONENT_ID, uri){
+                       @Override
+                       protected void onComponentTag(ComponentTag tag)
+                       {
+                               super.onComponentTag(tag);
+                               tag.setName("a");
+                       }
+               });
+
+               tester.startPage(page);
+
+               assertThat(tester.getLastResponseAsString()).contains(uri);
+       }
+
+       @Test
+       void escapesJavascriptQuotes() throws Exception
+       {
+               String unescaped = "javascript:alert('foo')";
+               MockPageWithOneComponent page = new MockPageWithOneComponent();
+               page.add(new ExternalLink(COMPONENT_ID, unescaped));
+
+               tester.startPage(page);
+
+               
assertThat(tester.getLastResponseAsString()).contains("javascript:alert(\\'foo\\')");
+       }
+
+       @Test
+       void allowsJavascriptSchemeInPopupTarget() throws Exception
+       {
+               String uri = "javascript:alert(1)";
+               MockPageWithOneComponent page = new MockPageWithOneComponent();
+               page.add(new ExternalLink(COMPONENT_ID, uri));
+
+               tester.startPage(page);
+
+               assertThat(tester.getLastResponseAsString()).contains(uri);
+       }
+       @Test
+       void escapeJavascriptQuotes() throws Exception
+       {
+               String uri = "javascript:alert('foo')";
+               MockPageWithOneComponent page = new MockPageWithOneComponent();
+               page.add(new ExternalLink(COMPONENT_ID, uri));
+
+               tester.startPage(page);
+
+               
assertThat(tester.getLastResponseAsString()).contains(JavaScriptUtils.escapeQuotes(uri));
+       }
+
        /**
         * @throws Exception
         */
diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/LinkTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/LinkTest.java
index 9ec3c048b9..995e13a7c9 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/LinkTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/LinkTest.java
@@ -16,15 +16,45 @@
  */
 package org.apache.wicket.markup.html.link;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
 import org.apache.wicket.MockPageWithLink;
+import org.apache.wicket.MockPageWithOneComponent;
+import org.apache.wicket.core.util.string.JavaScriptUtils;
+import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupNotFoundException;
 import org.apache.wicket.util.tester.WicketTestCase;
 import org.junit.jupiter.api.Test;
 
+import static org.apache.wicket.MockPageWithOneComponent.COMPONENT_ID;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 public class LinkTest extends WicketTestCase
 {
+
+    @Test
+    void allowsJavascriptSchemeInPopupsTarget()
+    {
+        var uri = "javascript:alert(1);";
+        MockPageWithOneComponent page = new MockPageWithOneComponent();
+        page.add(new PopupLink(COMPONENT_ID, uri));
+
+        tester.startPage(page);
+
+        assertThat(tester.getLastResponseAsString()).contains(uri);
+    }
+
+    @Test
+    void escapesJavascriptQuotesInPopupsTarget()
+    {
+        var uri = "javascript:alert('foo');";
+        MockPageWithOneComponent page = new MockPageWithOneComponent();
+        page.add(new PopupLink(COMPONENT_ID, uri));
+
+        tester.startPage(page);
+
+        
assertThat(tester.getLastResponseAsString()).contains("javascript:alert(\\'foo\\');");
+    }
+
     @Test
     void testWrongComponentId()
     {
@@ -43,4 +73,35 @@ public class LinkTest extends WicketTestCase
         mockPageWithLink.add(link);
         assertThrows(MarkupNotFoundException.class, () -> 
tester.startPage(mockPageWithLink));
     }
+
+    static class PopupLink extends Link<Void>
+    {
+               private final String uri;
+
+           public PopupLink(String id, String uri)
+        {
+            super(id);
+               this.uri = uri;
+                       setPopupSettings(new PopupSettings());
+        }
+
+        @Override
+        public void onClick()
+        {
+        }
+
+        @Override
+        protected void onComponentTag(ComponentTag tag)
+        {
+            super.onComponentTag(tag);
+            tag.setName("a");
+        }
+
+        @Override
+        protected CharSequence getURL()
+        {
+            return uri;
+        }
+    }
+
 }
diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/TestPageInsideSnakeCasePackage.html
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/TestPageInsideSnakeCasePackage.html
new file mode 100644
index 0000000000..ea75f28073
--- /dev/null
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/TestPageInsideSnakeCasePackage.html
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns:wicket="http://wicket.apache.org";>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+    <title>Test Page</title>
+</head>
+<body>
+none
+</body>
+</html>
diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/TestPageInsideSnakeCasePackage.java
similarity index 50%
copy from 
wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
copy to 
wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/TestPageInsideSnakeCasePackage.java
index 99a6612dbb..ee3288eaa8 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/link/ExternalLinkTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/TestPageInsideSnakeCasePackage.java
@@ -14,36 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.wicket.markup.html.link;
+package org.apache.wicket.markup.html.snake_case;
 
-import org.apache.wicket.util.tester.WicketTestCase;
-import org.junit.jupiter.api.Test;
+import org.apache.wicket.markup.html.WebPage;
 
-/**
- * Test ExternalLink (href="...")
- * 
- * <a href="https://issues.apache.org/jira/browse/WICKET-1016";></<a>
- */
-class ExternalLinkTest extends WicketTestCase
+public class TestPageInsideSnakeCasePackage extends WebPage
 {
-       /**
-        * @throws Exception
-        */
-       @Test
-    void renderExternalLink_1() throws Exception
-       {
-               
tester.getApplication().getMarkupSettings().setAutomaticLinking(true);
-               executeTest(ExternalLinkPage_1.class, 
"ExternalLinkPageExpectedResult_1.html");
-       }
-
-       /**
-        * @throws Exception
-        */
-       @Test
-    void renderExternalLink_2() throws Exception
-       {
-               
tester.getApplication().getMarkupSettings().setAutomaticLinking(true);
-               executeTest(ExternalLinkPage_2.class, 
"ExternalLinkPageExpectedResult_2.html");
-       }
-
 }
diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/style.css
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/snake_case/style.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/core/util/string/JavaScriptUtils.java
 
b/wicket-core/src/main/java/org/apache/wicket/core/util/string/JavaScriptUtils.java
index bd8629cb64..2eb4a28ed9 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/core/util/string/JavaScriptUtils.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/core/util/string/JavaScriptUtils.java
@@ -75,6 +75,26 @@ public class JavaScriptUtils
                return s;
        }
 
+       /**
+        * Escape single and double quotes so that they can be part of e.g. an 
alert call.
+        *
+        * Note: JSON values need to escape only the double quote, so this 
method wont help.
+        *
+        * @param input
+        *            the JavaScript which needs to be escaped
+        * @return Escaped version of the input
+        */
+       public static CharSequence escapeQuotesAndBackslash(final CharSequence 
input)
+       {
+               CharSequence s = input;
+               if (s != null)
+               {
+                       s = Strings.replaceAll(s, "\\", "\\\\");
+                       s = escapeQuotes(s);
+               }
+               return s;
+       }
+
        /**
         * Write a reference to a javascript file to the response object
         *
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/ExternalLink.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/ExternalLink.java
index 3217ee37d9..09607c8fc8 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/ExternalLink.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/ExternalLink.java
@@ -16,6 +16,7 @@
  */
 package org.apache.wicket.markup.html.link;
 
+import org.apache.wicket.core.util.string.JavaScriptUtils;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.OnEventHeaderItem;
@@ -188,7 +189,7 @@ public class ExternalLink extends AbstractLink
                {
                        if (popupSettings != null)
                        {
-                               popupSettings.setTarget("'" + url + "'");
+                               popupSettings.setTarget(url);
                                
response.render(OnEventHeaderItem.forComponent(this, "click",
                                        popupSettings.getPopupJavaScript()));
                                return;
@@ -205,8 +206,9 @@ public class ExternalLink extends AbstractLink
                                // in firefox when the element is quickly 
clicked 3 times a second request is
                                // generated during page load. This check 
ensures that the click is ignored
                                
response.render(OnEventHeaderItem.forComponent(this, "click",
-                                       "var win = 
this.ownerDocument.defaultView || this.ownerDocument.parentWindow; "
-                                               + "if (win == window) { 
window.location.href='" + url
+                                       "var win = 
this.ownerDocument.defaultView || this.ownerDocument.parentWindow; " //
+                                               + "if (win == window) { 
window.location.href='" //
+                                               + 
JavaScriptUtils.escapeQuotes(url) //
                                                + "'; } ;return false"));
                                return;
                        }
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/Link.java 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/Link.java
index 1943baf657..a2b8486403 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/Link.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/Link.java
@@ -414,7 +414,7 @@ public abstract class Link<T> extends AbstractLink 
implements IRequestListener,
                        // next check for popup settings
                        if (popupSettings != null)
                        {
-                               popupSettings.setTarget("'" + url + "'");
+                               popupSettings.setTarget(url.toString());
                                
response.render(OnEventHeaderItem.forComponent(this, "click",
                                        popupSettings.getPopupJavaScript()));
                                return;
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/PopupSettings.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/PopupSettings.java
index 82dc08f82f..e62b3e01be 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/PopupSettings.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/PopupSettings.java
@@ -16,6 +16,7 @@
  */
 package org.apache.wicket.markup.html.link;
 
+import org.apache.wicket.core.util.string.JavaScriptUtils;
 import org.apache.wicket.util.io.IClusterable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -155,8 +156,10 @@ public class PopupSettings implements IClusterable
                        windowTitle = windowTitle.replaceAll("\\W", "_");
                }
 
-           StringBuilder script = new StringBuilder("var w = window.open(" + 
target + ", '").append(
-                       windowTitle).append("', '");
+               StringBuilder script = new StringBuilder(//
+                       "var w = window.open('"//
+                               + JavaScriptUtils.escapeQuotes(target) //
+                               + "', '").append(windowTitle).append("', '");
 
                script.append("scrollbars=").append(flagToString(SCROLLBARS));
                script.append(",location=").append(flagToString(LOCATION_BAR));
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
 
b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
index 64c1845ee4..f50d8880d2 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/request/resource/PackageResource.java
@@ -16,15 +16,6 @@
  */
 package org.apache.wicket.request.resource;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.Locale;
-import java.util.Objects;
 import jakarta.servlet.http.HttpServletResponse;
 import org.apache.wicket.Application;
 import org.apache.wicket.IWicketInternalException;
@@ -53,6 +44,16 @@ import org.apache.wicket.util.string.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.Locale;
+import java.util.Objects;
+
 /**
  * Represents a localizable static resource.
  * <p>
@@ -555,38 +556,18 @@ public class PackageResource extends AbstractResource 
implements IStaticCacheabl
 
        private IResourceStream internalGetResourceStream(final String style, 
final Locale locale)
        {
+               if (!accept(absolutePath))
+               {
+                       throw new PackageResourceBlockedException(
+                               "Access denied to (static) package resource " + 
absolutePath + ". See IPackageResourceGuard");
+               }
+
                IResourceStreamLocator resourceStreamLocator = Application.get()
                        .getResourceSettings()
                        .getResourceStreamLocator();
                IResourceStream resourceStream = 
resourceStreamLocator.locate(getScope(), absolutePath,
                        style, variation, locale, null, false);
 
-               String realPath = absolutePath;
-               if (resourceStream instanceof IFixedLocationResourceStream)
-               {
-                       realPath = 
((IFixedLocationResourceStream)resourceStream).locationAsString();
-                       if (realPath != null)
-                       {
-                               int index = realPath.indexOf(absolutePath);
-                               if (index != -1)
-                               {
-                                       realPath = realPath.substring(index);
-                               }
-                       }
-                       else
-                       {
-                               realPath = absolutePath;
-                       }
-
-               }
-
-               if (accept(realPath) == false)
-               {
-                       throw new PackageResourceBlockedException(
-                               "Access denied to (static) package resource " + 
absolutePath +
-                                       ". See IPackageResourceGuard");
-               }
-
                if (resourceStream != null)
                {
                        resourceStream = new 
ProcessingResourceStream(resourceStream);
diff --git 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRenderer.java
 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRenderer.java
index c8d4343fb7..1c0d3d0a5a 100644
--- 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRenderer.java
+++ 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRenderer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.wicket.extensions.ajax.markup.html.autocomplete;
 
+import org.apache.wicket.core.util.string.JavaScriptUtils;
 import org.apache.wicket.request.Response;
 import org.apache.wicket.util.string.Strings;
 
@@ -50,7 +51,7 @@ public abstract class AbstractAutoCompleteRenderer<T> 
implements IAutoCompleteRe
                final CharSequence handler = 
getOnSelectJavaScriptExpression(object);
                if (handler != null)
                {
-                       response.write(" onselect=\"" + handler + '"');
+                       response.write(" onselect=\"" + 
Strings.escapeMarkup(handler) + '"');
                }
                response.write(">");
                renderChoice(object, response, criteria);
diff --git 
a/wicket-extensions/src/test/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRendererTest.java
 
b/wicket-extensions/src/test/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRendererTest.java
new file mode 100644
index 0000000000..2bf24f3bca
--- /dev/null
+++ 
b/wicket-extensions/src/test/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/AbstractAutoCompleteRendererTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.extensions.ajax.markup.html.autocomplete;
+
+import org.apache.wicket.mock.MockWebResponse;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.util.tester.WicketTestCase;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class AbstractAutoCompleteRendererTest extends WicketTestCase
+{
+       @Test
+       void escapeOnselectJSExpression()
+       {
+               var renderer = new Renderer("alert('hello');");
+               MockWebResponse response = new MockWebResponse();
+               renderer.render("foo", response, null);
+               assertThat(response.getTextResponse()).contains(
+                       "<li textvalue=\"foo\" 
onselect=\"alert(&#039;hello&#039;);\">foo</li>");
+       }
+
+       static class Renderer extends AbstractAutoCompleteRenderer<String>
+       {
+
+               final String expression;
+
+               Renderer(String expression)
+               {
+                       this.expression = expression;
+               }
+
+               @Override
+               protected CharSequence getOnSelectJavaScriptExpression(String 
item)
+               {
+                       return expression;
+               }
+
+               @Override
+               protected void renderChoice(String object, Response response, 
String criteria)
+               {
+                       response.write(object);
+               }
+
+               @Override
+               protected String getTextValue(String object)
+               {
+                       return object;
+               }
+       }
+}

Reply via email to