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 & 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("<script>x=1</script>", + 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; } }
