This is an automated email from the ASF dual-hosted git repository. papegaaij pushed a commit to branch wicket-10.x in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 34b36f2bc3f76030c38cac48996f0d8b893edc68 Author: Emond Papegaaij <[email protected]> AuthorDate: Wed Aug 19 22:24:56 2026 +0200 Escape the attribute values of a MetaDataHeaderItem as markup generateString escaped attribute names with Strings.escapeMarkup but ran the values through Strings.replaceAll(value, "\"", "\\\""). A backslash before a double quote means nothing in HTML, so a value holding a double quote ended its own attribute and whatever followed was read as further attributes. Values may come from an IModel, so they are not necessarily literals. WICKET-6178 set out to escape these values and this is what it left behind. They now go through Strings.escapeMarkup, like the names beside them and like every attribute ComponentTag writes. Two tests asserted the old output. testEscapeOnlyDoubleQuotes was named after the behaviour that was the problem and is renamed. HtmlImportHeaderItemTest expects an escaped ampersand in the href of a link tag, which is what a url holding two parameters has to carry, and is what ComponentTag writes for every other attribute. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- .../markup/head/HtmlImportHeaderItemTest.java | 7 +++-- .../wicket/markup/head/MetaDataHeaderItemTest.java | 35 ++++++++++++++++++++-- .../wicket/markup/head/MetaDataHeaderItem.java | 2 +- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/HtmlImportHeaderItemTest.java b/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/HtmlImportHeaderItemTest.java index 7d5eebfed3..1788a57406 100644 --- a/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/HtmlImportHeaderItemTest.java +++ b/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/HtmlImportHeaderItemTest.java @@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.apache.wicket.markup.html.basic.SimplePage; import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.util.string.Strings; import org.apache.wicket.util.tester.WicketTester; import org.junit.jupiter.api.Test; @@ -54,7 +55,9 @@ class HtmlImportHeaderItemTest MetaDataHeaderItem importLink = HtmlImportHeaderItem.forImportLinkTag(SimplePage.class, parameters, "monitor", true); - assertEquals("<link rel=\"import\" href=\"" + pageUrl + "\" media=\"monitor\" async />\n", - importLink.generateString()); + // the href is escaped as markup, like every other attribute Wicket writes. The url holds + // a literal & between its two parameters, which has to be written as an entity + assertEquals("<link rel=\"import\" href=\"" + Strings.escapeMarkup(pageUrl) + + "\" media=\"monitor\" async />\n", importLink.generateString()); } } diff --git a/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/MetaDataHeaderItemTest.java b/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/MetaDataHeaderItemTest.java index fc2c93b5b6..df4997e779 100644 --- a/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/MetaDataHeaderItemTest.java +++ b/wicket-core-tests/src/test/java/org/apache/wicket/markup/head/MetaDataHeaderItemTest.java @@ -43,12 +43,43 @@ class MetaDataHeaderItemTest assertEquals(expectedString, metaTag.generateString()); } + /** + * Attribute values are escaped as markup. A backslash before a double quote means nothing in + * HTML, so escaping that way left the value able to close its own attribute. + */ @Test - void testEscapeOnlyDoubleQuotes() throws Exception + void testEscapesAttributeValuesAsMarkup() throws Exception { - String expectedString = "<link rel=\"single quote \' double quotes\\\"\" href=\"\" />\n"; + String expectedString = "<link rel=\"single quote ' double quotes"\" href=\"\" />\n"; MetaDataHeaderItem metaTag = MetaDataHeaderItem.forLinkTag("single quote \' double quotes\"", ""); assertEquals(expectedString, metaTag.generateString()); } + + /** + * A value cannot end its attribute and add another one. + */ + @Test + void testAttributeValueCannotInjectAnotherAttribute() throws Exception + { + MetaDataHeaderItem metaTag = MetaDataHeaderItem.forMetaTag("description", + "x\" onload=\"x=1"); + + assertEquals("<meta name=\"description\" content=\"x" onload="x=1\" />\n", + metaTag.generateString()); + } + + /** + * The same for a value taken from a model. + */ + @Test + void testAttributeValueFromModelIsEscaped() throws Exception + { + MetaDataHeaderItem metaTag = MetaDataHeaderItem.forLinkTag("stylesheet", ""); + metaTag.addTagAttribute("title", Model.of("<script>x=1</script>")); + + assertEquals( + "<link rel=\"stylesheet\" href=\"\" title=\"<script>x=1</script>\" />\n", + metaTag.generateString()); + } } diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/head/MetaDataHeaderItem.java b/wicket-core/src/main/java/org/apache/wicket/markup/head/MetaDataHeaderItem.java index 6649ef2b66..05bfbfe211 100644 --- a/wicket-core/src/main/java/org/apache/wicket/markup/head/MetaDataHeaderItem.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/head/MetaDataHeaderItem.java @@ -131,7 +131,7 @@ public class MetaDataHeaderItem extends HeaderItem { buffer.append('=') .append('"') - .append(Strings.replaceAll(value.toString(), "\"", "\\\"")) + .append(Strings.escapeMarkup(value.toString())) .append('"'); } }
