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

papegaaij pushed a commit to branch wicket-8.x
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit f4ff8c8abcdc55292c41dbf8ffaf6ecc8d283096
Author: Emond Papegaaij <[email protected]>
AuthorDate: Wed Aug 19 22:24:25 2026 +0200

    Escape the model string a Button writes into a button element body
    
    Button clears escapeModelStrings in its constructor so that its value 
attribute
    is not encoded twice: ComponentTag#writeOutput encodes every attribute when 
it
    writes the tag. That reasoning covers the attribute and nothing else. When 
the
    tag is a button element, onComponentTagBody writes the same model string 
into
    the element body, and nothing encodes a body, so markup in the model was
    rendered as markup. Setting the flag back was not an alternative, because 
the
    value attribute would then be encoded twice.
    
    The body is escaped where it is written, and only when the flag is off. 
With the
    flag on getDefaultModelObjectAsString() has escaped already and escaping 
again
    would encode twice.
    
    whenButtonElement_thenModelObjectIsUsedAsTextContent asserted the old 
output and
    is renamed, since a button body now carries an escaped ampersand the same 
way
    the value attribute of an input always has.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 .../org/apache/wicket/markup/html/form/Button.java | 12 ++++++--
 .../apache/wicket/markup/html/form/ButtonTest.java | 33 ++++++++++++++++++++--
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Button.java 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Button.java
index 0b4bcdf91f..d89974cc4b 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Button.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Button.java
@@ -218,8 +218,16 @@ public class Button extends FormComponent<String> 
implements IFormSubmittingComp
                if ("button".equals(openTag.getName()))
                {
                        String modelObjectAsString = 
getDefaultModelObjectAsString();
-                       if (Strings.isEmpty(modelObjectAsString) == false) {
-                               replaceComponentTagBody(markupStream, openTag, 
modelObjectAsString);
+                       if (Strings.isEmpty(modelObjectAsString) == false)
+                       {
+                               // The constructor clears escapeModelStrings so 
that the value attribute is not
+                               // encoded twice, ComponentTag#writeOutput 
already encodes it. An element body is
+                               // not encoded anywhere, so escape here instead 
of relying on that flag. When an
+                               // application does set the flag, 
getDefaultModelObjectAsString() has escaped
+                               // already and escaping again would double 
encode.
+                               replaceComponentTagBody(markupStream, openTag,
+                                       getEscapeModelStrings() ? 
modelObjectAsString
+                                               : 
Strings.escapeMarkup(modelObjectAsString));
                                return;
                        }
                }
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java 
b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
index fe303e6a16..c442a3f6db 100644
--- 
a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
+++ 
b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
@@ -16,8 +16,10 @@
  */
 package org.apache.wicket.markup.html.form;
 
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
 
@@ -58,9 +60,14 @@ public class ButtonTest extends WicketTestCase
 
        /**
         * https://issues.apache.org/jira/browse/WICKET-6225
+        *
+        * The body of a button element is escaped once, like the value 
attribute of an input element
+        * is. Button clears escapeModelStrings in its constructor so that 
ComponentTag#writeOutput does
+        * not encode that attribute twice, and nothing encodes an element 
body, so the body is escaped
+        * where it is written instead.
         */
        @Test
-       public void whenButtonElement_thenModelObjectIsUsedAsTextContent()
+       public void 
whenButtonElement_thenModelObjectIsUsedAsEscapedTextContent()
        {
                
tester.getApplication().getMarkupSettings().setStripWicketTags(false);
                String text = "some text & another text";
@@ -77,7 +84,29 @@ public class ButtonTest extends WicketTestCase
                TagTester buttonTagTester = tester.getTagByWicketId("button");
                assertThat(buttonTagTester, is(notNullValue()));
                assertThat(buttonTagTester.getAttribute("value"), 
is(nullValue()));
-               assertThat(buttonTagTester.getValue(), is(equalTo(text)));
+               assertThat(buttonTagTester.getValue(), is(equalTo("some text 
&amp; another text")));
+       }
+
+       /**
+        * Markup in the model of a button does not become markup in the body 
of the button element.
+        */
+       @Test
+       public void whenButtonElement_thenMarkupInModelObjectIsEscaped()
+       {
+               
tester.getApplication().getMarkupSettings().setStripWicketTags(false);
+               TestPage testPage = new 
TestPage(Model.of("<script>x=1</script>")) {
+                       @Override
+                       public IResourceStream 
getMarkupResourceStream(MarkupContainer container, Class<?> containerClass)
+                       {
+                               return new StringResourceStream("<html><body>"
+                                               + "<form 
wicket:id=\"form\"><button 
wicket:id=\"button\"></button></form></body></html>");
+                       }
+               };
+               tester.startPage(testPage);
+
+               assertThat(tester.getTagByWicketId("button").getValue(),
+                       is(equalTo("&lt;script&gt;x=1&lt;/script&gt;")));
+               assertThat(tester.getLastResponseAsString(), 
not(containsString("<script>x=1</script>")));
        }
 
        /**

Reply via email to