This is an automated email from the ASF dual-hosted git repository. dashorst pushed a commit to branch wicket-8.x in repository https://gitbox.apache.org/repos/asf/wicket.git
commit af7c172081342f574b7501f5910ce0db90565ba8 Author: Emond Papegaaij <[email protected]> AuthorDate: Mon Oct 5 10:53:36 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. On this line Form#appendDefaultButtonField writes the markup id of the default button into such a handler. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- .../src/main/java/org/apache/wicket/Component.java | 19 +++++++++++-------- .../java/org/apache/wicket/IMarkupIdGenerator.java | 4 ++-- .../org/apache/wicket/ComponentIdCharactersTest.java | 10 +++++----- 3 files changed, 18 insertions(+), 15 deletions(-) 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 5ca9a1ed4e..04b9fff176 100644 --- a/wicket-core/src/main/java/org/apache/wicket/Component.java +++ b/wicket-core/src/main/java/org/apache/wicket/Component.java @@ -399,10 +399,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 @@ -767,8 +767,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() { @@ -2805,7 +2805,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 */ @@ -2865,8 +2865,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) @@ -4289,7 +4289,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. * diff --git a/wicket-core/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java b/wicket-core/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java index f6ca8f3510..ec93ac1fdd 100644 --- a/wicket-core/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/ComponentIdCharactersTest.java @@ -30,12 +30,12 @@ import org.junit.Test; */ public 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 b", "a b" }; /** 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über1"; + private static final String VALID_ID = "a b#c=d/e+f,g.h-i_j*k!lüber1"; /** */ @Test @@ -82,8 +82,8 @@ public class ComponentIdCharactersTest extends WicketTestCase @Test public 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\"")); Throwable e = assertRejected(WicketRuntimeException.class, () -> tester.startPage(new MarkupIdPage("a'b")), "a'b");
