You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by ju...@apache.org on 2026/09/25 14:45:20 UTC
(jspwiki) 16/33: JSPWIKI-1292 see jira for details
This is an automated email from the ASF dual-hosted git repository.
juanpablo-santos pushed a commit to branch master-2.x
in repository https://gitbox.apache.org/repos/asf/jspwiki.git
commit ff06e4996004ba27e74ee32c2432f4b308759fff
Author: Alex O'Ree <al...@apache.org>
AuthorDate: Sun Aug 23 12:17:12 2026 -0400
JSPWIKI-1292 see jira for details
---
.../apache/wiki/parser/JSPWikiMarkupParser.java | 4 ++--
.../java/org/apache/wiki/parser/PluginContent.java | 7 ++++--
.../wiki/render/WysiwygEditingRendererTest.java | 26 ++++++++++++++++++++++
.../main/webapp/templates/210/editors/CKeditor.jsp | 2 +-
.../main/webapp/templates/210/editors/TinyMCE.jsp | 2 +-
.../webapp/templates/default/editors/CKeditor.jsp | 2 +-
.../webapp/templates/default/editors/TinyMCE.jsp | 2 +-
.../webapp/templates/default/editors/wysiwyg.jsp | 2 +-
8 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/parser/JSPWikiMarkupParser.java b/jspwiki-main/src/main/java/org/apache/wiki/parser/JSPWikiMarkupParser.java
index 0998f6068..982def0aa 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/parser/JSPWikiMarkupParser.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/parser/JSPWikiMarkupParser.java
@@ -787,7 +787,7 @@ public class JSPWikiMarkupParser extends MarkupParser {
private Element handleAccessRule( String ruleLine ) {
if( m_wysiwygEditorMode ) {
- m_currentElement.addContent( "[" + ruleLine + "]" );
+ m_currentElement.addContent( "[" + TextUtil.escapeHTMLEntities( ruleLine ) + "]" );
}
if( !m_parseAccessRules ) {
return m_currentElement;
@@ -821,7 +821,7 @@ public class JSPWikiMarkupParser extends MarkupParser {
*/
private Element handleMetadata( final String link ) {
if( m_wysiwygEditorMode ) {
- m_currentElement.addContent( "[" + link + "]" );
+ m_currentElement.addContent( "[" + TextUtil.escapeHTMLEntities( link ) + "]" );
}
try {
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/parser/PluginContent.java b/jspwiki-main/src/main/java/org/apache/wiki/parser/PluginContent.java
index ae121de88..63f718cf1 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/parser/PluginContent.java
+++ b/jspwiki-main/src/main/java/org/apache/wiki/parser/PluginContent.java
@@ -32,6 +32,7 @@ import org.apache.wiki.api.plugin.Plugin;
import org.apache.wiki.api.plugin.PluginElement;
import org.apache.wiki.plugin.PluginManager;
import org.apache.wiki.preferences.Preferences;
+import org.apache.wiki.util.TextUtil;
import org.apache.wiki.variables.VariableManager;
import org.jdom2.Text;
@@ -147,8 +148,10 @@ public class PluginContent extends Text implements PluginElement {
if( wysiwygEditorMode && !m_pluginName.matches( EMITTABLE_PLUGINS ) ) {
result = PLUGIN_START + m_pluginName + SPACE;
- // convert newlines to <br> in case the plugin has a body.
- final String cmdLine = m_params.get( CMDLINE ).replaceAll( LINEBREAK, ELEMENT_BR );
+ // escape the raw command line first: this text node is emitted with output escaping
+ // disabled, so unescaped markup would reach the wysiwyg editor (and its <textarea>)
+ // as live HTML. Then convert newlines to <br> in case the plugin has a body.
+ final String cmdLine = TextUtil.escapeHTMLEntities( m_params.get( CMDLINE ) ).replaceAll( LINEBREAK, ELEMENT_BR );
result = result + cmdLine + PLUGIN_END;
} else {
final Boolean b = context.getVariable( Context.VAR_EXECUTE_PLUGINS );
diff --git a/jspwiki-main/src/test/java/org/apache/wiki/render/WysiwygEditingRendererTest.java b/jspwiki-main/src/test/java/org/apache/wiki/render/WysiwygEditingRendererTest.java
index dadf54f6f..67736f3e7 100644
--- a/jspwiki-main/src/test/java/org/apache/wiki/render/WysiwygEditingRendererTest.java
+++ b/jspwiki-main/src/test/java/org/apache/wiki/render/WysiwygEditingRendererTest.java
@@ -49,8 +49,15 @@ public class WysiwygEditingRendererTest {
}
private String render( final String s ) throws IOException {
+ return render( s, false );
+ }
+
+ private String render( final String s, final boolean wysiwygEditorMode ) throws IOException {
final Page dummyPage = Wiki.contents().page(testEngine,"TestPage");
final Context ctx = Wiki.context().create(testEngine,dummyPage);
+ if( wysiwygEditorMode ) {
+ ctx.setVariable( Context.VAR_WYSIWYG_EDITOR_MODE, Boolean.TRUE );
+ }
final StringReader in = new StringReader(s);
@@ -92,4 +99,23 @@ public class WysiwygEditingRendererTest {
Assertions.assertEquals( "<a class=\"createpage\" href=\"Non-existent Pagename with Spaces\">Non-existent Pagename with Spaces</a>", render(src) );
}
+ /**
+ * The wysiwyg render path echoes raw plugin command lines, access rules and metadata back into the
+ * generated HTML with output escaping disabled. Unescaped markup there breaks out of the wysiwyg
+ * editors' <textarea> (stored XSS). See the textarea sinks in templates/editors/*.jsp.
+ */
+ @Test
+ public void testWysiwygEchoedMarkupIsEscaped() throws Exception {
+ final String payload = "</textarea><script>alert(1)</script>";
+
+ String html = render( "[{SomePlugin " + payload + "}]", true );
+ Assertions.assertFalse( html.contains( payload ), html );
+
+ html = render( "[{SET foo='" + payload + "'}]", true );
+ Assertions.assertFalse( html.contains( payload ), html );
+
+ html = render( "[{ALLOW edit " + payload + "}]", true );
+ Assertions.assertFalse( html.contains( payload ), html );
+ }
+
}
diff --git a/jspwiki-war/src/main/webapp/templates/210/editors/CKeditor.jsp b/jspwiki-war/src/main/webapp/templates/210/editors/CKeditor.jsp
index d4bac805b..cb679ada4 100644
--- a/jspwiki-war/src/main/webapp/templates/210/editors/CKeditor.jsp
+++ b/jspwiki-war/src/main/webapp/templates/210/editors/CKeditor.jsp
@@ -167,7 +167,7 @@
</fieldset>
</wiki:CheckRequestContext>
- <textarea name="htmlPageText"><%=pageAsHtml%></textarea>
+ <textarea name="htmlPageText"><%=pageAsHtml.replace("&", "&").replace("<", "<").replace(">", ">")%></textarea>
</form>
<script type="text/javascript">
//<![CDATA[
diff --git a/jspwiki-war/src/main/webapp/templates/210/editors/TinyMCE.jsp b/jspwiki-war/src/main/webapp/templates/210/editors/TinyMCE.jsp
index 008876c7e..6abdb0b0e 100644
--- a/jspwiki-war/src/main/webapp/templates/210/editors/TinyMCE.jsp
+++ b/jspwiki-war/src/main/webapp/templates/210/editors/TinyMCE.jsp
@@ -163,7 +163,7 @@
</fieldset>
</wiki:CheckRequestContext>
- <textarea name="htmlPageText"><%=pageAsHtml%></textarea>
+ <textarea name="htmlPageText"><%=pageAsHtml.replace("&", "&").replace("<", "<").replace(">", ">")%></textarea>
</form>
<script type="text/javascript">
//<![CDATA[
diff --git a/jspwiki-war/src/main/webapp/templates/default/editors/CKeditor.jsp b/jspwiki-war/src/main/webapp/templates/default/editors/CKeditor.jsp
index 6a973858f..c737989a1 100644
--- a/jspwiki-war/src/main/webapp/templates/default/editors/CKeditor.jsp
+++ b/jspwiki-war/src/main/webapp/templates/default/editors/CKeditor.jsp
@@ -255,7 +255,7 @@
<div class="row edit-area livepreview previewcolumn"><%-- .livepreview .previewcolumn--%>
<div>
<textarea name="htmlPageText"
- autofocus="autofocus"><%=pageAsHtml.replace("&", "&")%></textarea>
+ autofocus="autofocus"><%=pageAsHtml.replace("&", "&").replace("<", "<").replace(">", ">")%></textarea>
</div>
<div class="ajaxpreview" >Preview comes here</div>
</div>
diff --git a/jspwiki-war/src/main/webapp/templates/default/editors/TinyMCE.jsp b/jspwiki-war/src/main/webapp/templates/default/editors/TinyMCE.jsp
index ec156fa62..3070b58b0 100644
--- a/jspwiki-war/src/main/webapp/templates/default/editors/TinyMCE.jsp
+++ b/jspwiki-war/src/main/webapp/templates/default/editors/TinyMCE.jsp
@@ -259,7 +259,7 @@
<div class="row edit-area livepreview previewcolumn"><%-- .livepreview .previewcolumn--%>
<div>
<textarea name="htmlPageText"
- autofocus="autofocus"><%=pageAsHtml.replace("&", "&")%></textarea>
+ autofocus="autofocus"><%=pageAsHtml.replace("&", "&").replace("<", "<").replace(">", ">")%></textarea>
</div>
<div class="ajaxpreview" >Preview comes here</div>
</div>
diff --git a/jspwiki-war/src/main/webapp/templates/default/editors/wysiwyg.jsp b/jspwiki-war/src/main/webapp/templates/default/editors/wysiwyg.jsp
index 2c4617a50..14049c8ff 100644
--- a/jspwiki-war/src/main/webapp/templates/default/editors/wysiwyg.jsp
+++ b/jspwiki-war/src/main/webapp/templates/default/editors/wysiwyg.jsp
@@ -257,7 +257,7 @@
To avoid this, double escape the & char => so &lt; is converted to <
--%>
<textarea name="htmlPageText"
- autofocus="autofocus"><%= pageAsHtml.replace("&", "&")%></textarea>
+ autofocus="autofocus"><%= pageAsHtml.replace("&", "&").replace("<", "<").replace(">", ">")%></textarea>
</div>
<div class="ajaxpreview">Preview comes here</div>
</div>