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
The following commit(s) were added to refs/heads/master by this push:
new c97c75fa76 Document that VelocityPanel renders markup and needs a
trusted template
c97c75fa76 is described below
commit c97c75fa76307c8c3c548c77d9c267da7f3830d6
Author: Emond Papegaaij <[email protected]>
AuthorDate: Mon Aug 31 21:43:06 2026 +0200
Document that VelocityPanel renders markup and needs a trusted template
The panel writes the template's output into the page as markup, re-parsed
as the panel's own component markup, and neither that output nor the values
interpolated into it are escaped. None of this was written down.
Say so on the class, and say what follows: the template has to be authored
by the developer, because Velocity Template Language can invoke methods on
the objects in its context, so a template an untrusted party can influence
is a code execution problem rather than a markup one. That is a stricter
requirement than for a markup file, which cannot run code.
Also note on escapeHtml() that it escapes the whole rendered output,
including the developer's own tags, so it is not a way to escape
interpolated values while still emitting markup, and that
escapeModelStrings does not apply to this panel.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.../src/main/asciidoc/helloWorld/helloWorld_1.adoc | 2 +-
.../wicket/velocity/markup/html/VelocityPanel.java | 29 ++++++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc
b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc
index 185ab2a4e0..f011943180 100644
--- a/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc
+++ b/wicket-user-guide/src/main/asciidoc/helloWorld/helloWorld_1.adoc
@@ -15,7 +15,7 @@ Wicket is available as a binary package on the main site
http://wicket.apache.o
|wicket-ioc | This module provides common classes to support Inversion Of
Control. It's used by both Spring and Guice integration module. | wicket-core,
wicket-tester
|wicket-guice | This module provides integration with the dependency injection
framework developed by Google. | wicket-core, wicket-ioc, wicket-tester
|wicket-spring | This module provides integration with Spring framework. |
wicket-core, wicket-ioc, wicket-tester
-|wicket-velocity | This module provides panels and utility class to integrate
Wicket with Velocity template engine. | wicket-core, wicket-tester
+|wicket-velocity | This module provides panels and utility class to integrate
Wicket with Velocity template engine. Templates are rendered as markup and are
not escaped, and neither are the values interpolated into them, so both must be
authored by the developer: a Velocity template can invoke methods on the
objects in its context, and one built from user input is a code execution risk
rather than only a markup one. | wicket-core, wicket-tester
|wicket-jmx| This module provides panels and utility class to integrate Wicket
with Java Management Extensions. | wicket-core, wicket-tester
|wicket-objectsizeof-agent | Provides integration with Java agent libraries
and instrumentation tools. | wicket-core
|===
diff --git
a/wicket-velocity/src/main/java/org/apache/wicket/velocity/markup/html/VelocityPanel.java
b/wicket-velocity/src/main/java/org/apache/wicket/velocity/markup/html/VelocityPanel.java
index 986b6ef86a..b942cd5b1b 100644
---
a/wicket-velocity/src/main/java/org/apache/wicket/velocity/markup/html/VelocityPanel.java
+++
b/wicket-velocity/src/main/java/org/apache/wicket/velocity/markup/html/VelocityPanel.java
@@ -47,6 +47,28 @@ import org.apache.wicket.util.string.Strings;
* <b>Note:</b> Be sure to properly initialize the Velocity engine before using
* {@link VelocityPanel }.
* </p>
+ * <p>
+ * <b>This panel renders markup.</b> By default the template's output is
written into the page as
+ * markup, not as text: it is re-parsed as the panel's own component markup,
which is what allows a
+ * template to contribute Wicket components. Nothing on this path is escaped.
See
+ * {@link #escapeHtml()}.
+ * </p>
+ * <p>
+ * <b>The template must be authored by the developer.</b> Never build one from
user input, and never
+ * use {@code #evaluate} or {@code #parse} on a value that came from a user.
Velocity Template
+ * Language can invoke methods on the objects in its context, so a template an
untrusted party can
+ * influence is a code execution problem, not merely a markup one — escaping
the output would not
+ * help, and would give a false sense of safety. A template needs more care
than a {@code .html}
+ * markup file, not the same: both are developer-authored, but markup cannot
run code on the server
+ * and a Velocity template can.
+ * </p>
+ * <p>
+ * <b>Values interpolated into the template are not escaped either.</b> The
Velocity context is
+ * built from this panel's model, and a {@code $reference} is substituted
verbatim, so a model value
+ * carrying markup reaches the page as markup. Escape such values yourself
before putting them in
+ * the model, or keep user-supplied content out of it. Note that {@code
escapeModelStrings}, which
+ * governs escaping elsewhere in Wicket, has no effect on this panel.
+ * </p>
*/
public abstract class VelocityPanel extends Panel
implements
@@ -191,6 +213,13 @@ public abstract class VelocityPanel extends Panel
* is, without escaping.</b> A template that interpolates user input or
other dynamic
* content then puts it in the page unescaped.
* </p>
+ * <p>
+ * Returning {@code true} escapes the <em>whole</em> rendered output,
including any markup the
+ * template itself contains, so the developer's own tags are then shown
as visible text. This is
+ * therefore not a way to escape interpolated values while still
emitting markup; there is no
+ * such mode. If the template must produce markup, keep untrusted
content out of the model
+ * instead.
+ * </p>
*
* @return whether to escape HTML characters. The default value is
false.
*/