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

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

commit 2c1633e525539ad005c8f25d1ed76a1be28ff389
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]>
---
 .../apache/wicket/markup/html/form/ButtonTest.java | 32 ++++++++++++++++++++--
 .../org/apache/wicket/markup/html/form/Button.java | 12 ++++++--
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
index 587d9e9af9..deff919da7 100644
--- 
a/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
+++ 
b/wicket-core-tests/src/test/java/org/apache/wicket/markup/html/form/ButtonTest.java
@@ -17,6 +17,7 @@
 package org.apache.wicket.markup.html.form;
 
 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.assertNull;
 
@@ -57,9 +58,14 @@ 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
-       void whenButtonElement_thenModelObjectIsUsedAsTextContent()
+       void whenButtonElement_thenModelObjectIsUsedAsEscapedTextContent()
        {
                
tester.getApplication().getMarkupSettings().setStripWicketTags(false);
                String text = "some text & another text";
@@ -76,7 +82,29 @@ class ButtonTest extends WicketTestCase
                TagTester buttonTagTester = tester.getTagByWicketId("button");
                assertNotNull(buttonTagTester);
                assertNull(buttonTagTester.getAttribute("value"));
-               assertEquals(text, buttonTagTester.getValue());
+               assertEquals("some text &amp; another text", 
buttonTagTester.getValue());
+       }
+
+       /**
+        * Markup in the model of a button does not become markup in the body 
of the button element.
+        */
+       @Test
+       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);
+
+               assertEquals("&lt;script&gt;x=1&lt;/script&gt;",
+                       tester.getTagByWicketId("button").getValue());
+               
assertFalse(tester.getLastResponseAsString().contains("<script>x=1</script>"));
        }
 
        /**
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 cf358efcb4..52b62283aa 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
@@ -228,8 +228,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;
                        }
                }

Reply via email to