This is an automated email from the ASF dual-hosted git repository. dashorst pushed a commit to branch wicket-10.x in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 3cea021af6b296532f30fd869922a9b3b99b4b43 Author: Emond Papegaaij <[email protected]> AuthorDate: Mon Oct 5 10:53:44 2026 +0200 Reject '&' in a component id and a markup id A browser decodes the character references in an attribute before it runs the script in it, and for a numeric reference the closing ';' is optional. An id written into an event handler attribute without HTML escaping could therefore still end its string literal: ''' decodes to a quote, and ')', ';' and the like to other characters the check rejects. '&' is now rejected along with them. No such handler is left on this line; '&' is rejected here as well, so that the check means the same on 8.x, 9.x and 10.x. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- .../org/apache/wicket/ComponentIdCharactersTest.java | 10 +++++----- .../src/main/java/org/apache/wicket/Component.java | 19 +++++++++++-------- .../java/org/apache/wicket/IMarkupIdGenerator.java | 4 ++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/wicket-core-tests/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java b/wicket-core-tests/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java index 500359cf2e..611800ae8f 100644 --- a/wicket-core-tests/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java +++ b/wicket-core-tests/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java @@ -34,12 +34,12 @@ import org.junit.jupiter.api.Test; */ class ComponentIdCharactersTest extends WicketTestCase { - private static final String[] INVALID_IDS = { "a'b", "a\"b", "a`b", "a\\b", "a;b", "a(b", - "a)b", "a[b", "a]b", "a{b", "a}b", "a<b", "a>b", "a\nb", "a\rb", "a\tb", "a\u0000b", + private static final String[] INVALID_IDS = { "a'b", "a\"b", "a`b", "a\\b", "a;b", "a(b", "a)b", + "a[b", "a]b", "a{b", "a}b", "a<b", "a>b", "a&b", "a\nb", "a\rb", "a\tb", "a\u0000b", "a\u2028b", "a\u2029b" }; /** Characters that cannot end a JavaScript string literal are still allowed */ - private static final String VALID_ID = "a b&c=d/e+f,g.h-i_j*k!l\u00fcber1"; + private static final String VALID_ID = "a b#c=d/e+f,g.h-i_j*k!l\u00fcber1"; @Test void componentIdMayContainOtherCharacters() @@ -81,8 +81,8 @@ class ComponentIdCharactersTest extends WicketTestCase @Test void markupIdFromTheMarkupIsChecked() { - tester.startPage(new MarkupIdPage("a-b_c.d1 e&f")); - assertTrue(tester.getLastResponseAsString().contains("id=\"a-b_c.d1 e&f\"")); + tester.startPage(new MarkupIdPage("a-b_c.d1 e#f")); + assertTrue(tester.getLastResponseAsString().contains("id=\"a-b_c.d1 e#f\"")); WicketRuntimeException e = assertThrows(WicketRuntimeException.class, () -> tester.startPage(new MarkupIdPage("a'b"))); diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java b/wicket-core/src/main/java/org/apache/wicket/Component.java index 326544557a..1a344e392a 100644 --- a/wicket-core/src/main/java/org/apache/wicket/Component.java +++ b/wicket-core/src/main/java/org/apache/wicket/Component.java @@ -401,10 +401,10 @@ public abstract class Component private static final String MARKUP_ID_ATTR_NAME = "id"; /** Characters a component id or a markup id must not contain, see {@link #isValidId(String)} */ - private static final String INVALID_ID_CHARS = "'\"`\\()[]{}<>;"; + private static final String INVALID_ID_CHARS = "'\"`\\()[]{}<>;&"; private static final String INVALID_ID_MESSAGE = - "must not contain quotes, backslashes, brackets, ';' or control characters."; + "must not contain quotes, backslashes, brackets, ';', '&' or control characters."; /** * Meta data key for line precise error logging for the moment of addition. Made package private @@ -769,8 +769,8 @@ public abstract class Component /** * @return The 'id' attribute from the associated markup tag * @throws WicketRuntimeException - * if the id contains a quote, a backslash, a bracket, {@code ';'} or a control - * character + * if the id contains a quote, a backslash, a bracket, {@code ';'}, {@code '&'} or a + * control character */ public final String getMarkupIdFromMarkup() { @@ -2816,7 +2816,7 @@ public abstract class Component /** * Set markup ID, which must be String or Integer. A String must not contain quotes, - * backslashes, brackets, {@code ';'} or control characters. + * backslashes, brackets, {@code ';'}, {@code '&'} or control characters. * * @param markupId */ @@ -2876,8 +2876,8 @@ public abstract class Component * * @param markupId * markup id value or null to clear any previous user defined value. It must not - * contain quotes, backslashes, brackets, {@code ';'} or control characters, because - * Wicket writes it into the JavaScript it generates. + * contain quotes, backslashes, brackets, {@code ';'}, {@code '&'} or control + * characters, because Wicket writes it into the JavaScript it generates. * @return this for chaining */ public Component setMarkupId(String markupId) @@ -4302,7 +4302,10 @@ public abstract class Component * Checks the characters of a component id or a markup id. Wicket writes both into the * JavaScript it generates, the markup id as it is and the component id as part of an input name, * so characters that can end a JavaScript string literal or statement are not allowed: quotes, - * backslashes, brackets, {@code ';'} and control characters, line breaks included. + * backslashes, brackets, {@code ';'} and control characters, line breaks included. {@code '&'} + * is not allowed either: in a script written into an attribute, such as an event handler, the + * browser decodes a character reference before the script runs, so {@code '} would end the + * literal as well. * * @param id * the id to check diff --git a/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java b/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java index da72b3aa9f..4ad2041a28 100644 --- a/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java +++ b/wicket-core/src/main/java/org/apache/wicket/IMarkupIdGenerator.java @@ -26,8 +26,8 @@ public interface IMarkupIdGenerator * Generates markup id for the given component * <p> * Wicket writes the markup id into the JavaScript it generates, without escaping it. A - * generated markup id must therefore not contain quotes, backslashes, brackets, {@code ';'} or - * control characters. An id the component already has, from + * generated markup id must therefore not contain quotes, backslashes, brackets, {@code ';'}, + * {@code '&'} or control characters. An id the component already has, from * {@link Component#setMarkupId(String)} or from the id attribute in its markup, has been * checked already. *
