CVE-2023-32070 (published 2023-05-10T18:15Z)

XWiki Platform is a generic wiki platform. Prior to version 14.6-rc-1, HTML rendering didn't check for dangerous attributes/attribute values. This allowed cross-site scripting (XSS) attacks via attributes and link URLs, e.g., supported in XWiki syntax. This has been patched in XWiki 14.6-rc-1. There are no known workarounds apart from upgrading to a fixed version.

CVSS v3 base score: 6.1, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)

Weakness information:
cwe_id: CWE-79
cwe_name: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
extended_description: 
            Cross-site scripting (XSS) vulnerabilities occur when:
            
               Untrusted data enters a web application, typically from a web request.
               The web application dynamically generates a web page that contains this untrusted data.
               During page generation, the application does not prevent the data from containing content that is executable by a web browser, such as JavaScript, HTML tags, HTML attributes, mouse events, Flash, ActiveX, etc.
               A victim visits the generated web page through a web browser, which contains malicious script that was injected using the untrusted data.
               Since the script comes from a web page that was sent by the web server, the victim's web browser executes the malicious script in the context of the web server's domain.
               This effectively violates the intention of the web browser's same-origin policy, which states that scripts in one domain should not be able to access resources or run code in a different domain.
            
            There are three main kinds of XSS:
            
               
                  Type 1: Reflected XSS (or Non-Persistent) - 
         			The server reads data directly from the HTTP request and reflects it back in the HTTP response. Reflected XSS exploits occur when an attacker causes a victim to supply dangerous content to a vulnerable web application, which is then reflected back to the victim and executed by the web browser. The most common mechanism for delivering malicious content is to include it as a parameter in a URL that is posted publicly or e-mailed directly to the victim. URLs constructed in this manner constitute the core of many phishing schemes, whereby an attacker convinces a victim to visit a URL that refers to a vulnerable site. After the site reflects the attacker's content back to the victim, the content is executed by the victim's browser.
               
                  Type 2: Stored XSS (or Persistent) - 
               The application stores dangerous data in a database, message forum, visitor log, or other trusted data store. At a later time, the dangerous data is subsequently read back into the application and included in dynamic content. From an attacker's perspective, the optimal place to inject malicious content is in an area that is displayed to either many users or particularly interesting users. Interesting users typically have elevated privileges in the application or interact with sensitive data that is valuable to the attacker. If one of these users executes malicious content, the attacker may be able to perform privileged operations on behalf of the user or gain access to sensitive data belonging to the user. For example, the attacker might inject XSS into a log message, which might not be handled properly when an administrator views the logs.
            
               
                  Type 0: DOM-Based XSS - 
               In DOM-based XSS, the client performs the injection of XSS into the page; in the other types, the server performs the injection. DOM-based XSS generally involves server-controlled, trusted script that is sent to the client, such as Javascript that performs sanity checks on a form before the user submits it. If the server-supplied script processes user-supplied data and then injects it back into the web page (such as with dynamic HTML), then DOM-based XSS is possible.
            
            
            Once the malicious script is injected, the attacker can perform a variety of malicious activities. The attacker could transfer private information, such as cookies that may include session information, from the victim's machine to the attacker. The attacker could send malicious requests to a web site on behalf of the victim, which could be especially dangerous to the site if the victim has administrator privileges to manage that site. Phishing attacks could be used to emulate trusted web sites and trick the victim into entering a password, allowing the attacker to compromise the victim's account on that web site. Finally, the script could exploit a vulnerability in the web browser itself possibly taking over the victim's machine, sometimes referred to as "drive-by hacking."
            In many cases, the attack can be launched without the victim even being aware of it. Even with careful users, attackers frequently use a variety of methods to encode the malicious portion of the attack, such as URL encoding or Unicode, so the request looks less suspicious.
         
         

Fix information:
repo_url: https://github.com/xwiki/xwiki-rendering
commit_details: repo_url: https://github.com/xwiki/xwiki-rendering
author: Michael Hamann
author_date: 2022-04-29 10:33:38+02:00
msg: XRENDERING-663: Restrict allowed attributes in HTML rendering

* Change HTML renderers to only print allowed attributes and elements.
* Add prefix to forbidden attributes to preserve them in XWiki syntax.
* Adapt tests to expect that invalid attributes get a prefix.
repository: repo_url: https://github.com/xwiki/xwiki-rendering
repo_name: xwiki/xwiki-rendering
description: The XWiki Rendering Engine
repo_language: Java
owner: xwiki
file_changes: filename: escape15.test
change_type: ModificationType.MODIFY
diff: @@ -20,11 +20,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><span class="wikiexternallink"><a param="value" href="refe||rence">lab&gt;&gt;el~</a></span></p>
+<p><span class="wikiexternallink"><a data-xwiki-translated-attribute-param="value" href="refe||rence">lab&gt;&gt;el~</a></span></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|url|-|refe||rence--><span class="wikiexternallink"><a param="value" href="refe||rence">lab&gt;&gt;el~</a></span><!--stopwikilink--></p>
+<p><!--startwikilink:false|-|url|-|refe||rence--><span class="wikiexternallink"><a data-xwiki-translated-attribute-param="value" href="refe||rence">lab&gt;&gt;el~</a></span><!--stopwikilink--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -32,4 +32,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|url|-|refe||rence--><span class="wikiexternallink"><a param="value" href="refe||rence">lab&gt;&gt;el~</a></span><!--stopwikilink--></p>
\ No newline at end of file
+<p><!--startwikilink:false|-|url|-|refe||rence--><span class="wikiexternallink"><a data-xwiki-translated-attribute-param="value" href="refe||rence">lab&gt;&gt;el~</a></span><!--stopwikilink--></p>
\ No newline at end of file

programming_language: Lua
filename: group9.test
change_type: ModificationType.MODIFY
diff: @@ -29,7 +29,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<div param="value"><p>some text</p></div><div param="value"><p>some text</p></div>
+<div data-xwiki-translated-attribute-param="value"><p>some text</p></div><div data-xwiki-translated-attribute-param="value"><p>some text</p></div>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -45,4 +45,4 @@ some text
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<div param="value"><p>some text</p></div><div param="value"><p>some text</p></div>
\ No newline at end of file
+<div data-xwiki-translated-attribute-param="value"><p>some text</p></div><div data-xwiki-translated-attribute-param="value"><p>some text</p></div>
\ No newline at end of file

programming_language: SQL
filename: horizontalline5.test
change_type: ModificationType.MODIFY
diff: @@ -12,7 +12,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<hr param="value"/>
+<hr data-xwiki-translated-attribute-param="value"/>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -21,4 +21,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<html><hr param="value"/></html>
\ No newline at end of file
+<html><hr data-xwiki-translated-attribute-param="value"/></html>
\ No newline at end of file

programming_language: Lua
filename: italic8.test
change_type: ModificationType.MODIFY
diff: @@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><em><span a="b">something</span></em></p>
+<p><em><span data-xwiki-translated-attribute-a="b">something</span></em></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------

programming_language: Lua
filename: definitionlist7.test
change_type: ModificationType.MODIFY
diff: @@ -21,7 +21,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<dl param="value"><dt>title</dt><dd>definition</dd></dl>
+<dl data-xwiki-translated-attribute-param="value"><dt>title</dt><dd>definition</dd></dl>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -31,7 +31,7 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<dl param="value"><dt>title</dt><dd>definition</dd></dl>
+<dl data-xwiki-translated-attribute-param="value"><dt>title</dt><dd>definition</dd></dl>
 .#-----------------------------------------------------
 .expect|plain/1.0
 .#-----------------------------------------------------

programming_language: Lua
filename: list13.test
change_type: ModificationType.MODIFY
diff: @@ -42,7 +42,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<ul param="value"><li>item 1<ul param2="value2"><li>item 1.1<ul><li>item 1.1.1</li></ul></li></ul></li></ul>
+<ul data-xwiki-translated-attribute-param="value"><li>item 1<ul data-xwiki-translated-attribute-param2="value2"><li>item 1.1<ul><li>item 1.1.1</li></ul></li></ul></li></ul>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -54,4 +54,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<ul param="value"><li>item 1<ul param2="value2"><li>item 1.1<ul><li>item 1.1.1</li></ul></li></ul></li></ul>
\ No newline at end of file
+<ul data-xwiki-translated-attribute-param="value"><li>item 1<ul data-xwiki-translated-attribute-param2="value2"><li>item 1.1<ul><li>item 1.1.1</li></ul></li></ul></li></ul>
\ No newline at end of file

programming_language: SQL
filename: list8.test
change_type: ModificationType.MODIFY
diff: @@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<ul param1="value1" param2="value2"><li>item</li></ul>
+<ul data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2"><li>item</li></ul>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -25,4 +25,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<html><ul param1="value1" param2="value2"><li>item</li></ul></html>
\ No newline at end of file
+<html><ul data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2"><li>item</li></ul></html>
\ No newline at end of file

programming_language: Lua
filename: macro10.test
change_type: ModificationType.MODIFY
diff: @@ -44,12 +44,12 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<span param="value">formatmacro2</span><p><span a="b"><span param="value">formatmacro3</span> text</span></p><p><span a="b">text</span><span param="value">formatmacro4</span></p>
+<span data-xwiki-translated-attribute-param="value">formatmacro2</span><p><span data-xwiki-translated-attribute-a="b"><span data-xwiki-translated-attribute-param="value">formatmacro3</span> text</span></p><p><span data-xwiki-translated-attribute-a="b">text</span><span data-xwiki-translated-attribute-param="value">formatmacro4</span></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<!--startmacro:testformatmacro|-|--><span param="value">formatmacro2</span><!--stopmacro--><p><span a="b"><!--startmacro:testformatmacro|-|--><span param="value">formatmacro3</span><!--stopmacro--> text</span></p><p><span a="b">text</span><!--startmacro:testformatmacro|-|--><span param="value">formatmacro4</span><!--stopmacro--></p>
+<!--startmacro:testformatmacro|-|--><span data-xwiki-translated-attribute-param="value">formatmacro2</span><!--stopmacro--><p><span data-xwiki-translated-attribute-a="b"><!--startmacro:testformatmacro|-|--><span data-xwiki-translated-attribute-param="value">formatmacro3</span><!--stopmacro--> text</span></p><p><span data-xwiki-translated-attribute-a="b">text</span><!--startmacro:testformatmacro|-|--><span data-xwiki-translated-attribute-param="value">formatmacro4</span><!--stopmacro--></p>
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<!--startmacro:testformatmacro|-|--><span param="value">formatmacro2</span><!--stopmacro--><p><span a="b"><!--startmacro:testformatmacro|-|--><span param="value">formatmacro3</span><!--stopmacro--> text</span></p><p><span a="b">text</span><!--startmacro:testformatmacro|-|--><span param="value">formatmacro4</span><!--stopmacro--></p>
\ No newline at end of file
+<!--startmacro:testformatmacro|-|--><span data-xwiki-translated-attribute-param="value">formatmacro2</span><!--stopmacro--><p><span data-xwiki-translated-attribute-a="b"><!--startmacro:testformatmacro|-|--><span data-xwiki-translated-attribute-param="value">formatmacro3</span><!--stopmacro--> text</span></p><p><span data-xwiki-translated-attribute-a="b">text</span><!--startmacro:testformatmacro|-|--><span data-xwiki-translated-attribute-param="value">formatmacro4</span><!--stopmacro--></p>
\ No newline at end of file

programming_language: HTML
filename: paragraph6.test
change_type: ModificationType.MODIFY
diff: @@ -105,7 +105,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p param1="value1" param2="value2"><span param3="value3">hello</span> world</p><p><span param4="valueA">hello&nbsp;</span><span param4="valueB">world</span></p><p><strong><span param5="value4">hello</span></strong><span param5="value4">&nbsp;world</span></p><p><span param6="valueA">hello&nbsp;</span><span param7="valueB">world</span></p><p>before<span param="value">x</span><strong>y</strong>after</p><p>12<strong>34<span param="value">56</span>78</strong>90</p><p><span param="value">1<em>2</em></span><em>3</em></p><p><strong><span param1="value1">1</span></strong><strong><span param2="value2">2</span></strong></p>
+<p data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2"><span data-xwiki-translated-attribute-param3="value3">hello</span> world</p><p><span data-xwiki-translated-attribute-param4="valueA">hello&nbsp;</span><span data-xwiki-translated-attribute-param4="valueB">world</span></p><p><strong><span data-xwiki-translated-attribute-param5="value4">hello</span></strong><span data-xwiki-translated-attribute-param5="value4">&nbsp;world</span></p><p><span data-xwiki-translated-attribute-param6="valueA">hello&nbsp;</span><span data-xwiki-translated-attribute-param7="valueB">world</span></p><p>before<span data-xwiki-translated-attribute-param="value">x</span><strong>y</strong>after</p><p>12<strong>34<span data-xwiki-translated-attribute-param="value">56</span>78</strong>90</p><p><span data-xwiki-translated-attribute-param="value">1<em>2</em></span><em>3</em></p><p><strong><span data-xwiki-translated-attribute-param1="value1">1</span></strong><strong><span data-xwiki-translated-attribute-param2="value2">2</span></strong></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------

programming_language: Lua
filename: quote3.test
change_type: ModificationType.MODIFY
diff: @@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<blockquote param1="value1" param2="value2"><p>line</p></blockquote>
+<blockquote data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2"><p>line</p></blockquote>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -25,4 +25,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<blockquote param1="value1" param2="value2"><p>line</p></blockquote>
\ No newline at end of file
+<blockquote data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2"><p>line</p></blockquote>
\ No newline at end of file

programming_language: Lua
filename: section6.test
change_type: ModificationType.MODIFY
diff: @@ -17,7 +17,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<h1 id="Hheader" class="wikigeneratedid" param="value"><span>header</span></h1>
+<h1 id="Hheader" class="wikigeneratedid" data-xwiki-translated-attribute-param="value"><span>header</span></h1>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -26,4 +26,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<html><h1 id="Hheader" class="wikigeneratedid" param="value"><span>header</span></h1></html>
\ No newline at end of file
+<html><h1 id="Hheader" class="wikigeneratedid" data-xwiki-translated-attribute-param="value"><span>header</span></h1></html>
\ No newline at end of file

programming_language: Lua
filename: strikedout4.test
change_type: ModificationType.MODIFY
diff: @@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><del><span a="b">something</span></del></p>
+<p><del><span data-xwiki-translated-attribute-a="b">something</span></del></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------

programming_language: Lua
filename: subscript2.test
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,7 @@
 .input|xhtml/1.0
 .# Verify that SUB tag parameters are recognized.
 .#-----------------------------------------------------
-<html><p><sub a="b">something</sub></p></html>
+<html><p><sub data-xwiki-translated-attribute-a="b">something</sub></p></html>
 .#-----------------------------------------------------
 .expect|event/1.0
 .#-----------------------------------------------------
@@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><sub><span a="b">something</span></sub></p>
+<p><sub><span data-xwiki-translated-attribute-a="b">something</span></sub></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------

programming_language: Lua
filename: superscript2.test
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,7 @@
 .input|xhtml/1.0
 .# Verify that SUP tag parameters are recognized.
 .#-----------------------------------------------------
-<html><p><sup a="b">something</sup></p></html>
+<html><p><sup data-xwiki-translated-attribute-a="b">something</sup></p></html>
 .#-----------------------------------------------------
 .expect|event/1.0
 .#-----------------------------------------------------
@@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><sup><span a="b">something</span></sup></p>
+<p><sup><span data-xwiki-translated-attribute-a="b">something</span></sup></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------

programming_language: Lua
filename: table3.test
change_type: ModificationType.MODIFY
diff: @@ -43,7 +43,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<table a="b"><tr c="d"><th e="f" scope="col"><span g="h">cell1</span></th><td i="j"><span k="l">cell2</span></td></tr></table><table a="b"><tr c="d"><th e="f" scope="col"><span g="h">cell1</span></th><td i="j"><span k="l">cell2</span></td></tr></table>
+<table data-xwiki-translated-attribute-a="b"><tr data-xwiki-translated-attribute-c="d"><th data-xwiki-translated-attribute-e="f" scope="col"><span data-xwiki-translated-attribute-g="h">cell1</span></th><td data-xwiki-translated-attribute-i="j"><span k="l">cell2</span></td></tr></table><table data-xwiki-translated-attribute-a="b"><tr data-xwiki-translated-attribute-c="d"><th data-xwiki-translated-attribute-e="f" scope="col"><span data-xwiki-translated-attribute-g="h">cell1</span></th><td data-xwiki-translated-attribute-i="j"><span k="l">cell2</span></td></tr></table>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -55,4 +55,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<table a="b"><tr c="d"><th e="f" scope="col"><span g="h">cell1</span></th><td i="j"><span k="l">cell2</span></td></tr></table><table a="b"><tr c="d"><th e="f" scope="col"><span g="h">cell1</span></th><td i="j"><span k="l">cell2</span></td></tr></table>
\ No newline at end of file
+<table data-xwiki-translated-attribute-a="b"><tr data-xwiki-translated-attribute-c="d"><th data-xwiki-translated-attribute-e="f" scope="col"><span data-xwiki-translated-attribute-g="h">cell1</span></th><td data-xwiki-translated-attribute-i="j"><span k="l">cell2</span></td></tr></table><table data-xwiki-translated-attribute-a="b"><tr data-xwiki-translated-attribute-c="d"><th data-xwiki-translated-attribute-e="f" scope="col"><span data-xwiki-translated-attribute-g="h">cell1</span></th><td data-xwiki-translated-attribute-i="j"><span k="l">cell2</span></td></tr></table>
\ No newline at end of file

programming_language: Lua
filename: verbatim6.test
change_type: ModificationType.MODIFY
diff: @@ -12,7 +12,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<pre param="value">abc</pre>
+<pre data-xwiki-translated-attribute-param="value">abc</pre>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -21,4 +21,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<html><pre param="value">abc</pre></html>
+<html><pre data-xwiki-translated-attribute-param="value">abc</pre></html>

programming_language: Lua
filename: verbatim7.test
change_type: ModificationType.MODIFY
diff: @@ -16,7 +16,7 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p param="value"><span param2="value2"><tt class="wikimodel-verbatim">abc</tt></span></p>
+<p data-xwiki-translated-attribute-param="value"><span data-xwiki-translated-attribute-param2="value2"><tt class="wikimodel-verbatim">abc</tt></span></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -25,4 +25,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p param="value"><span param2="value2"><tt class="wikimodel-verbatim">abc</tt></span></p>
\ No newline at end of file
+<p data-xwiki-translated-attribute-param="value"><span data-xwiki-translated-attribute-param2="value2"><tt class="wikimodel-verbatim">abc</tt></span></p>
\ No newline at end of file

programming_language: Lua
filename: image1.test
change_type: ModificationType.MODIFY
diff: @@ -16,11 +16,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><img src="imageurl" param1="value1" param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><br/><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/></p>
+<p><img src="imageurl" data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><br/><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startimage:false|-|attach|-|my.png--><img src="imageurl" param1="value1" param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><!--stopimage--><br/><!--startimage:false|-|attach|-|Space.ExistingPage@my.png--><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
+<p><!--startimage:false|-|attach|-|my.png--><img src="imageurl" data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><!--stopimage--><br/><!--startimage:false|-|attach|-|Space.ExistingPage@my.png--><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -29,4 +29,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startimage:false|-|attach|-|my.png--><img src="imageurl" param1="value1" param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><!--stopimage--><br/><!--startimage:false|-|attach|-|Space.ExistingPage@my.png--><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
\ No newline at end of file
+<p><!--startimage:false|-|attach|-|my.png--><img src="imageurl" data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><!--stopimage--><br/><!--startimage:false|-|attach|-|Space.ExistingPage@my.png--><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
\ No newline at end of file

programming_language: Markdown
filename: image12.test
change_type: ModificationType.MODIFY
diff: @@ -65,8 +65,8 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<img src="imageurl" param1="value1" param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><div class="figcaption"><p>Image <strong>Caption</strong></p></div><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><div class="figcaption"><p>Caption</p><ul><li>With</li><li>nested</li><li>list <span class="wikiexternallink"><a href="https://xwiki.org">and link</a></span> and [[fake link]].</li></ul></div>
+<img src="imageurl" data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><div class="figcaption"><p>Image <strong>Caption</strong></p></div><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><div class="figcaption"><p>Caption</p><ul><li>With</li><li>nested</li><li>list <span class="wikiexternallink"><a href="https://xwiki.org">and link</a></span> and [[fake link]].</li></ul></div>
 .#-----------------------------------------------------
 .expect|html/5.0
 .#-----------------------------------------------------
-<figure class="image"><img src="imageurl" param1="value1" param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><figcaption><p>Image <strong>Caption</strong></p></figcaption></figure><figure class="image"><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><figcaption><p>Caption</p><ul><li>With</li><li>nested</li><li>list <span class="wikiexternallink"><a href="https://xwiki.org">and link</a></span> and [[fake link]].</li></ul></figcaption></figure>
\ No newline at end of file
+<figure class="image"><img src="imageurl" data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" id="Imy.png" class="wikigeneratedid" alt="my.png"/><figcaption><p>Image <strong>Caption</strong></p></figcaption></figure><figure class="image"><img src="imageurl" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><figcaption><p>Caption</p><ul><li>With</li><li>nested</li><li>list <span class="wikiexternallink"><a href="https://xwiki.org">and link</a></span> and [[fake link]].</li></ul></figcaption></figure>
\ No newline at end of file

programming_language: Markdown
filename: image8.test
change_type: ModificationType.MODIFY
diff: @@ -15,11 +15,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><img src="imageurl" param2="value2" id="ISpace.ExistingPage40my.png3Fparam13Dvalue1" class="wikigeneratedid" alt="Space.ExistingPage@my.png?param1=value1"/></p>
+<p><img src="imageurl" data-xwiki-translated-attribute-param2="value2" id="ISpace.ExistingPage40my.png3Fparam13Dvalue1" class="wikigeneratedid" alt="Space.ExistingPage@my.png?param1=value1"/></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png?param1=value1--><img src="imageurl" param2="value2" id="ISpace.ExistingPage40my.png3Fparam13Dvalue1" class="wikigeneratedid" alt="Space.ExistingPage@my.png?param1=value1"/><!--stopimage--></p>
+<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png?param1=value1--><img src="imageurl" data-xwiki-translated-attribute-param2="value2" id="ISpace.ExistingPage40my.png3Fparam13Dvalue1" class="wikigeneratedid" alt="Space.ExistingPage@my.png?param1=value1"/><!--stopimage--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -27,4 +27,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png?param1=value1--><img src="imageurl" param2="value2" id="ISpace.ExistingPage40my.png3Fparam13Dvalue1" class="wikigeneratedid" alt="Space.ExistingPage@my.png?param1=value1"/><!--stopimage--></p>
\ No newline at end of file
+<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png?param1=value1--><img src="imageurl" data-xwiki-translated-attribute-param2="value2" id="ISpace.ExistingPage40my.png3Fparam13Dvalue1" class="wikigeneratedid" alt="Space.ExistingPage@my.png?param1=value1"/><!--stopimage--></p>
\ No newline at end of file

programming_language: PHP
filename: image9.test
change_type: ModificationType.MODIFY
diff: @@ -15,11 +15,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><img src="imageurl?param1=value1" param2="value2" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/></p>
+<p><img src="imageurl?param1=value1" data-xwiki-translated-attribute-param2="value2" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png|-|queryString="param1=value1"--><img src="imageurl?param1=value1" param2="value2" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
+<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png|-|queryString="param1=value1"--><img src="imageurl?param1=value1" data-xwiki-translated-attribute-param2="value2" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.1
 .#-----------------------------------------------------
@@ -27,4 +27,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png|-|queryString="param1=value1"--><img src="imageurl?param1=value1" param2="value2" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
\ No newline at end of file
+<p><!--startimage:false|-|attach|-|Space.ExistingPage@my.png|-|queryString="param1=value1"--><img src="imageurl?param1=value1" data-xwiki-translated-attribute-param2="value2" id="ISpace.ExistingPage40my.png" class="wikigeneratedid" alt="Space.ExistingPage@my.png"/><!--stopimage--></p>
\ No newline at end of file

programming_language: Markdown
filename: links14.test
change_type: ModificationType.MODIFY
diff: @@ -16,11 +16,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><span class="wikiexternallink"><a param="value" href="http://xwiki.org"><img src="imageurl" height="100" width="100" id="Iattach.png" class="wikigeneratedid" alt="attach.png"/></a></span></p>
+<p><span class="wikiexternallink"><a data-xwiki-translated-attribute-param="value" href="http://xwiki.org"><img src="imageurl" height="100" width="100" id="Iattach.png" class="wikigeneratedid" alt="attach.png"/></a></span></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|url|-|http://xwiki.org--><span class="wikiexternallink"><a param="value" href="http://xwiki.org"><!--startimage:false|-|attach|-|attach.png--><img src="imageurl" height="100" width="100" id="Iattach.png" class="wikigeneratedid" alt="attach.png"/><!--stopimage--></a></span><!--stopwikilink--></p>
+<p><!--startwikilink:false|-|url|-|http://xwiki.org--><span class="wikiexternallink"><a data-xwiki-translated-attribute-param="value" href="http://xwiki.org"><!--startimage:false|-|attach|-|attach.png--><img src="imageurl" height="100" width="100" id="Iattach.png" class="wikigeneratedid" alt="attach.png"/><!--stopimage--></a></span><!--stopwikilink--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -28,4 +28,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|url|-|http://xwiki.org--><span class="wikiexternallink"><a param="value" href="http://xwiki.org"><!--startimage:false|-|attach|-|attach.png--><img src="imageurl" height="100" width="100" id="Iattach.png" class="wikigeneratedid" alt="attach.png"/><!--stopimage--></a></span><!--stopwikilink--></p>
\ No newline at end of file
+<p><!--startwikilink:false|-|url|-|http://xwiki.org--><span class="wikiexternallink"><a data-xwiki-translated-attribute-param="value" href="http://xwiki.org"><!--startimage:false|-|attach|-|attach.png--><img src="imageurl" height="100" width="100" id="Iattach.png" class="wikigeneratedid" alt="attach.png"/><!--stopimage--></a></span><!--stopwikilink--></p>
\ No newline at end of file

programming_language: Lua
filename: links15.test
change_type: ModificationType.MODIFY
diff: @@ -18,11 +18,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><span class="wikiattachmentlink"><a param1="value1" param2="value2" href="attachmenturl"><span class="wikigeneratedlinkcontent">my.png</span></a></span><br/><span class="wikiattachmentlink"><a href="attachmenturl"><span class="wikigeneratedlinkcontent">Space.ExistingPage@my.png</span></a></span></p>
+<p><span class="wikiattachmentlink"><a data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" href="attachmenturl"><span class="wikigeneratedlinkcontent">my.png</span></a></span><br/><span class="wikiattachmentlink"><a href="attachmenturl"><span class="wikigeneratedlinkcontent">Space.ExistingPage@my.png</span></a></span></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:true|-|attach|-|my.png--><span class="wikiattachmentlink"><a param1="value1" param2="value2" href="attachmenturl"><span class="wikigeneratedlinkcontent">my.png</span></a></span><!--stopwikilink--><br/><!--startwikilink:true|-|attach|-|Space.ExistingPage@my.png--><span class="wikiattachmentlink"><a href="attachmenturl"><span class="wikigeneratedlinkcontent">Space.ExistingPage@my.png</span></a></span><!--stopwikilink--></p>
+<p><!--startwikilink:true|-|attach|-|my.png--><span class="wikiattachmentlink"><a data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" href="attachmenturl"><span class="wikigeneratedlinkcontent">my.png</span></a></span><!--stopwikilink--><br/><!--startwikilink:true|-|attach|-|Space.ExistingPage@my.png--><span class="wikiattachmentlink"><a href="attachmenturl"><span class="wikigeneratedlinkcontent">Space.ExistingPage@my.png</span></a></span><!--stopwikilink--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -31,4 +31,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:true|-|attach|-|my.png--><span class="wikiattachmentlink"><a param1="value1" param2="value2" href="attachmenturl"><span class="wikigeneratedlinkcontent">my.png</span></a></span><!--stopwikilink--><br/><!--startwikilink:true|-|attach|-|Space.ExistingPage@my.png--><span class="wikiattachmentlink"><a href="attachmenturl"><span class="wikigeneratedlinkcontent">Space.ExistingPage@my.png</span></a></span><!--stopwikilink--></p>
\ No newline at end of file
+<p><!--startwikilink:true|-|attach|-|my.png--><span class="wikiattachmentlink"><a data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" href="attachmenturl"><span class="wikigeneratedlinkcontent">my.png</span></a></span><!--stopwikilink--><br/><!--startwikilink:true|-|attach|-|Space.ExistingPage@my.png--><span class="wikiattachmentlink"><a href="attachmenturl"><span class="wikigeneratedlinkcontent">Space.ExistingPage@my.png</span></a></span><!--stopwikilink--></p>
\ No newline at end of file

programming_language: Markdown
filename: links19.test
change_type: ModificationType.MODIFY
diff: @@ -4,7 +4,7 @@
 .# that the XHTML Renderer uses. Note that for now the HREF value is considered containing
 .# XWiki link syntax.
 .#----------------------------------------------------------------------------------------------
-<p><a href="http://reference" param1="value1">http://reference</a></p>
+<p><a href="http://reference" data-xwiki-translated-attribute-param1="value1">http://reference</a></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -29,4 +29,4 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><span class="wikiexternallink"><a param1="value1" href="http://reference">http://reference</a></span></p>
\ No newline at end of file
+<p><span class="wikiexternallink"><a data-xwiki-translated-attribute-param1="value1" href="http://reference">http://reference</a></span></p>
\ No newline at end of file

programming_language: Lua
filename: links2.test
change_type: ModificationType.MODIFY
diff: @@ -21,11 +21,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><span class="wikilink"><a param2="value2" href="viewurl?param1=value1#anchor"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span></p>
+<p><span class="wikilink"><a data-xwiki-translated-attribute-param2="value2" href="viewurl?param1=value1#anchor"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|doc|-|Space.ExistingPage|-|queryString="param1=value1" anchor="anchor"--><span class="wikilink"><a param2="value2" href="viewurl?param1=value1#anchor"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--></p>
+<p><!--startwikilink:false|-|doc|-|Space.ExistingPage|-|queryString="param1=value1" anchor="anchor"--><span class="wikilink"><a data-xwiki-translated-attribute-param2="value2" href="viewurl?param1=value1#anchor"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -37,4 +37,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|doc|-|Space.ExistingPage|-|queryString="param1=value1" anchor="anchor"--><span class="wikilink"><a param2="value2" href="viewurl?param1=value1#anchor"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--></p>
\ No newline at end of file
+<p><!--startwikilink:false|-|doc|-|Space.ExistingPage|-|queryString="param1=value1" anchor="anchor"--><span class="wikilink"><a data-xwiki-translated-attribute-param2="value2" href="viewurl?param1=value1#anchor"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--></p>
\ No newline at end of file

programming_language: Lua
filename: links8.test
change_type: ModificationType.MODIFY
diff: @@ -19,11 +19,11 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><span class="wikilink"><a param1="value1" param2="value2" href="viewurl"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><br/><span class="wikicreatelink"><a param="value" href="editurl">label</a></span></p>
+<p><span class="wikilink"><a data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" href="viewurl"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><br/><span class="wikicreatelink"><a data-xwiki-translated-attribute-param="value" href="editurl">label</a></span></p>
 .#-----------------------------------------------------
 .expect|annotatedxhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|doc|-|Space.ExistingPage--><span class="wikilink"><a param1="value1" param2="value2" href="viewurl"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--><br/><!--startwikilink:false|-|doc|-|Space.UnknownPage--><span class="wikicreatelink"><a param="value" href="editurl">label</a></span><!--stopwikilink--></p>
+<p><!--startwikilink:false|-|doc|-|Space.ExistingPage--><span class="wikilink"><a data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" href="viewurl"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--><br/><!--startwikilink:false|-|doc|-|Space.UnknownPage--><span class="wikicreatelink"><a data-xwiki-translated-attribute-param="value" href="editurl">label</a></span><!--stopwikilink--></p>
 .#-----------------------------------------------------
 .expect|xwiki/2.0
 .#-----------------------------------------------------
@@ -32,4 +32,4 @@ endDocument
 .#-----------------------------------------------------
 .input|xhtml/1.0
 .#-----------------------------------------------------
-<p><!--startwikilink:false|-|doc|-|Space.ExistingPage--><span class="wikilink"><a param1="value1" param2="value2" href="viewurl"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--><br/><!--startwikilink:false|-|doc|-|Space.UnknownPage--><span class="wikicreatelink"><a param="value" href="editurl">label</a></span><!--stopwikilink--></p>
\ No newline at end of file
+<p><!--startwikilink:false|-|doc|-|Space.ExistingPage--><span class="wikilink"><a data-xwiki-translated-attribute-param1="value1" data-xwiki-translated-attribute-param2="value2" href="viewurl"><span class="wikigeneratedlinkcontent">Space.ExistingPage</span></a></span><!--stopwikilink--><br/><!--startwikilink:false|-|doc|-|Space.UnknownPage--><span class="wikicreatelink"><a data-xwiki-translated-attribute-param="value" href="editurl">label</a></span><!--stopwikilink--></p>
\ No newline at end of file

programming_language: Lua
filename: HTMLMacroXHTMLRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -29,6 +29,7 @@
 import org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageRenderer;
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Renderer that generates XHTML from a XDOM resulting from the parsing of text containing HTML mixed with wiki syntax.
@@ -57,9 +58,13 @@ public class HTMLMacroXHTMLRenderer extends AbstractHTMLMacroRenderer
     @Inject
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     protected AbstractChainingPrintRenderer getSyntaxRenderer()
     {
-        return new XHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, getListenerChain());
+        return new XHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, this.htmlElementSanitizer,
+            getListenerChain());
     }
 }

programming_language: Java
filename: HTMLMacroAnnotatedHTML5Renderer.java
change_type: ModificationType.MODIFY
diff: @@ -30,6 +30,7 @@
 import org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageRenderer;
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Renderer that generates Annotated HTML5 from a XDOM resulting from the parsing of text containing HTML mixed with
@@ -59,9 +60,13 @@ public class HTMLMacroAnnotatedHTML5Renderer extends AbstractHTMLMacroRenderer
     @Inject
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     protected AbstractChainingPrintRenderer getSyntaxRenderer()
     {
-        return new AnnotatedHTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, getListenerChain());
+        return new AnnotatedHTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, this.htmlElementSanitizer,
+            getListenerChain());
     }
 }

programming_language: Java
filename: HTMLMacroAnnotatedXHTMLRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -30,6 +30,7 @@
 import org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageRenderer;
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Renderer that generates Annotated XHTML from a XDOM resulting from the parsing of text containing HTML mixed with
@@ -61,9 +62,13 @@ public class HTMLMacroAnnotatedXHTMLRenderer extends AbstractHTMLMacroRenderer
     @Named("annotated")
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     protected AbstractChainingPrintRenderer getSyntaxRenderer()
     {
-        return new AnnotatedXHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, getListenerChain());
+        return new AnnotatedXHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, this.htmlElementSanitizer,
+            getListenerChain());
     }
 }

programming_language: Java
filename: HTMLMacroHTML5Renderer.java
change_type: ModificationType.MODIFY
diff: @@ -30,6 +30,7 @@
 import org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageRenderer;
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Renderer that generates HTML5 from a XDOM resulting from the parsing of text containing HTML mixed with
@@ -59,9 +60,13 @@ public class HTMLMacroHTML5Renderer extends AbstractHTMLMacroRenderer
     @Inject
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     protected AbstractChainingPrintRenderer getSyntaxRenderer()
     {
-        return new HTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, getListenerChain());
+        return new HTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, this.htmlElementSanitizer,
+            getListenerChain());
     }
 }

programming_language: Java
filename: AnnotatedHTML5ChainingRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -28,6 +28,7 @@
 import org.xwiki.rendering.listener.MetaData;
 import org.xwiki.rendering.listener.chaining.BlockStateChainingListener;
 import org.xwiki.rendering.listener.chaining.ListenerChain;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Convert listener events to annotated HTML5. See {@link AnnotatedHTML5Renderer} for more details on what Annotated
@@ -55,12 +56,13 @@ public class AnnotatedHTML5ChainingRenderer extends HTML5ChainingRenderer
      * @param imageRenderer the object to render image events into XHTML. This is done so that it's pluggable because
      *            image rendering depends on how the underlying system wants to handle it. For example for XWiki we
      *            check if the image exists as a document attachments, we get its URL, etc.
+     * @param htmlElementSanitizer the HTML element sanitizer to use
      * @param listenerChain the chain of listener filters used to compute various states
      */
     public AnnotatedHTML5ChainingRenderer(XHTMLLinkRenderer linkRenderer,
-            XHTMLImageRenderer imageRenderer, ListenerChain listenerChain)
+            XHTMLImageRenderer imageRenderer, HTMLElementSanitizer htmlElementSanitizer, ListenerChain listenerChain)
     {
-        super(linkRenderer, imageRenderer, listenerChain);
+        super(linkRenderer, imageRenderer, htmlElementSanitizer, listenerChain);
 
         this.macroRenderer = new XHTMLMacroRenderer();
 

programming_language: Java
filename: AnnotatedHTML5Renderer.java
change_type: ModificationType.MODIFY
diff: @@ -34,6 +34,7 @@
 import org.xwiki.rendering.listener.chaining.ListenerChain;
 import org.xwiki.rendering.listener.chaining.MetaDataStateChainingListener;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Generates Annotated HTML5 (ie HTML5 containing metadata information, for example macro definition or
@@ -67,6 +68,9 @@ public class AnnotatedHTML5Renderer extends AbstractChainingPrintRenderer implem
     @Named("annotated")
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     public void initialize() throws InitializationException
     {
@@ -79,6 +83,7 @@ public void initialize() throws InitializationException
         chain.addListener(new BlockStateChainingListener(chain));
         chain.addListener(new EmptyBlockChainingListener(chain));
         chain.addListener(new MetaDataStateChainingListener(chain));
-        chain.addListener(new AnnotatedHTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, chain));
+        chain.addListener(new AnnotatedHTML5ChainingRenderer(this.linkRenderer, this.imageRenderer,
+            this.htmlElementSanitizer, chain));
     }
 }

programming_language: Java
filename: monospace2.out.txt
change_type: ModificationType.MODIFY
diff: @@ -1 +1 @@
-<p><span a="b" class="monospace">monospace</span></p>
\ No newline at end of file
+<p><span data-xwiki-translated-attribute-a="b" class="monospace">monospace</span></p>
\ No newline at end of file

programming_language: SQL
filename: AnnotatedXHTMLChainingRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -25,6 +25,7 @@
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
 import org.xwiki.rendering.listener.MetaData;
 import org.xwiki.rendering.listener.chaining.ListenerChain;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Convert listener events to annotated XHTML. See {@link AnnotatedXHTMLChainingRenderer} for more details on
@@ -52,12 +53,13 @@ public class AnnotatedXHTMLChainingRenderer extends XHTMLChainingRenderer
      * @param imageRenderer the object to render image events into XHTML. This is done so that it's pluggable because
      *            image rendering depends on how the underlying system wants to handle it. For example for XWiki we
      *            check if the image exists as a document attachments, we get its URL, etc.
+     * @param htmlElementSanitizer the sanitizer to use for sanitizing HTML elements and attributes
      * @param listenerChain the chain of listener filters used to compute various states
      */
     public AnnotatedXHTMLChainingRenderer(XHTMLLinkRenderer linkRenderer,
-        XHTMLImageRenderer imageRenderer, ListenerChain listenerChain)
+        XHTMLImageRenderer imageRenderer, HTMLElementSanitizer htmlElementSanitizer, ListenerChain listenerChain)
     {
-        super(linkRenderer, imageRenderer, listenerChain);
+        super(linkRenderer, imageRenderer, htmlElementSanitizer, listenerChain);
 
         this.macroRenderer = new XHTMLMacroRenderer();
 

programming_language: Java
filename: AnnotatedXHTMLRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -34,6 +34,7 @@
 import org.xwiki.rendering.listener.chaining.ListenerChain;
 import org.xwiki.rendering.listener.chaining.MetaDataStateChainingListener;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Generates Annotated XHTML (ie XHTML containing metadata information, for example macro definition or
@@ -67,6 +68,9 @@ public class AnnotatedXHTMLRenderer extends AbstractChainingPrintRenderer implem
     @Named("annotated")
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     public void initialize() throws InitializationException
     {
@@ -79,6 +83,7 @@ public void initialize() throws InitializationException
         chain.addListener(new BlockStateChainingListener(chain));
         chain.addListener(new EmptyBlockChainingListener(chain));
         chain.addListener(new MetaDataStateChainingListener(chain));
-        chain.addListener(new AnnotatedXHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, chain));
+        chain.addListener(new AnnotatedXHTMLChainingRenderer(this.linkRenderer, this.imageRenderer,
+            this.htmlElementSanitizer, chain));
     }
 }

programming_language: Java
filename: HTML5ChainingRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -20,6 +20,7 @@
 package org.xwiki.rendering.internal.renderer.html5;
 
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import org.xwiki.rendering.internal.renderer.xhtml.XHTMLChainingRenderer;
@@ -27,6 +28,7 @@
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
 import org.xwiki.rendering.listener.Format;
 import org.xwiki.rendering.listener.chaining.ListenerChain;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Convert listener events to HTML5.
@@ -53,13 +55,14 @@ public class HTML5ChainingRenderer extends XHTMLChainingRenderer
      * @param imageRenderer the object to render image events into XHTML. This is done so that it's pluggable because
      * image rendering depends on how the underlying system wants to handle it. For example for XWiki we check if the
      * image exists as a document attachments, we get its URL, etc.
+     * @param htmlElementSanitizer the sanitizer to use for sanitizing HTML elements and attributes
      * @param listenerChain the chain of listener filters used to compute various states
      */
     public HTML5ChainingRenderer(XHTMLLinkRenderer linkRenderer,
-            XHTMLImageRenderer imageRenderer,
+            XHTMLImageRenderer imageRenderer, HTMLElementSanitizer htmlElementSanitizer,
             ListenerChain listenerChain)
     {
-        super(linkRenderer, imageRenderer, listenerChain);
+        super(linkRenderer, imageRenderer, htmlElementSanitizer, listenerChain);
     }
 
     @Override
@@ -67,8 +70,7 @@ public void beginFormat(Format format, Map<String, String> parameters)
     {
         // Right now, the only difference with the super class is about the "monospace" format
         if (format == Format.MONOSPACE) {
-            Map<String, String> attributes = new HashMap<>();
-            attributes.putAll(parameters);
+            Map<String, String> attributes = new LinkedHashMap<>(parameters);
             String cssClass = "monospace";
             // The element may already have a class
             if (attributes.containsKey(PROP_CLASS)) {

programming_language: Java
filename: HTML5Renderer.java
change_type: ModificationType.MODIFY
diff: @@ -34,6 +34,7 @@
 import org.xwiki.rendering.listener.chaining.ListenerChain;
 import org.xwiki.rendering.listener.chaining.MetaDataStateChainingListener;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Generates HTML5 from a {@link org.xwiki.rendering.block.XDOM} object being traversed.
@@ -62,6 +63,9 @@ public class HTML5Renderer extends AbstractChainingPrintRenderer implements Init
     @Inject
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     public void initialize() throws InitializationException
     {
@@ -74,7 +78,8 @@ public void initialize() throws InitializationException
         chain.addListener(new BlockStateChainingListener(chain));
         chain.addListener(new EmptyBlockChainingListener(chain));
         chain.addListener(new MetaDataStateChainingListener(chain));
-        chain.addListener(new HTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, chain));
+        chain.addListener(new HTML5ChainingRenderer(this.linkRenderer, this.imageRenderer, this.htmlElementSanitizer,
+            chain));
     }
 }
 

programming_language: Java
filename: HTML5ChainingRendererTest.java
change_type: ModificationType.MODIFY
diff: @@ -24,9 +24,9 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.xwiki.rendering.internal.renderer.html5.HTML5ChainingRenderer;
 import org.xwiki.rendering.internal.renderer.xhtml.image.XHTMLImageRenderer;
 import org.xwiki.rendering.internal.renderer.xhtml.link.XHTMLLinkRenderer;
-import org.xwiki.rendering.internal.renderer.html5.HTML5ChainingRenderer;
 import org.xwiki.rendering.listener.Format;
 import org.xwiki.rendering.listener.chaining.ListenerChain;
 import org.xwiki.rendering.renderer.printer.DefaultWikiPrinter;
@@ -58,7 +58,7 @@ public void setUp() throws Exception
         linkRenderer = mock(XHTMLLinkRenderer.class);
         imageRenderer = mock(XHTMLImageRenderer.class);
         listenerChain = new ListenerChain();
-        chainingRenderer = new HTML5ChainingRenderer(linkRenderer, imageRenderer, listenerChain);
+        chainingRenderer = new HTML5ChainingRenderer(linkRenderer, imageRenderer, null, listenerChain);
         printer = new DefaultWikiPrinter();
         chainingRenderer.setPrinter(printer);
     }

programming_language: Java
filename: XHTMLXWikiGeneratorListener.java
change_type: ModificationType.MODIFY
diff: @@ -19,10 +19,12 @@
  */
 package org.xwiki.rendering.internal.parser.xhtml.wikimodel;
 
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.xwiki.rendering.internal.parser.wikimodel.DefaultXWikiGeneratorListener;
 import org.xwiki.rendering.listener.Listener;
@@ -32,6 +34,7 @@
 import org.xwiki.rendering.parser.ResourceReferenceParser;
 import org.xwiki.rendering.parser.StreamParser;
 import org.xwiki.rendering.renderer.PrintRendererFactory;
+import org.xwiki.rendering.renderer.printer.XHTMLWikiPrinter;
 import org.xwiki.rendering.syntax.Syntax;
 import org.xwiki.rendering.util.IdGenerator;
 import org.xwiki.rendering.wikimodel.WikiFormat;
@@ -204,7 +207,7 @@ private static WikiParameters cleanParametersFromMetadata(WikiParameters paramet
         for (WikiParameter parameter : parameters) {
             boolean acceptParameter = !(parameter.getKey().startsWith(METADATA_ATTRIBUTE_PREFIX)
                 || (
-                    parameter.getKey().equals(CLASS_ATTRIBUTE) && parameter.getValue().equals(METADATA_CONTAINER_CLASS)
+                parameter.getKey().equals(CLASS_ATTRIBUTE) && parameter.getValue().equals(METADATA_CONTAINER_CLASS)
             ));
             if (acceptParameter) {
                 wikiParameters = wikiParameters.addParameter(parameter.getKey(), parameter.getValue());
@@ -288,4 +291,47 @@ public void endFormat(WikiFormat format)
             super.endFormat(format);
         }
     }
+
+    @Override
+    protected Map<String, String> convertParameters(WikiParameters params)
+    {
+        return maybeRemoveAttributePrefix(super.convertParameters(params));
+    }
+
+    @Override
+    protected Pair<Map<String, String>, Map<String, String>> convertAndSeparateParameters(WikiParameters params)
+    {
+        Pair<Map<String, String>, Map<String, String>> result = super.convertAndSeparateParameters(params);
+        Map<String, String> genericParameters = result.getRight();
+
+        if (!genericParameters.isEmpty()) {
+            genericParameters = maybeRemoveAttributePrefix(genericParameters);
+        }
+
+        return new ImmutablePair<>(result.getLeft(), genericParameters);
+    }
+
+    private Map<String, String> maybeRemoveAttributePrefix(Map<String, String> attributes)
+    {
+        Map<String, String> result;
+
+        if (!attributes.isEmpty()) {
+            result = new LinkedHashMap<>();
+
+            for (Map.Entry<String, String> entry : attributes.entrySet()) {
+                String newKey;
+                if (entry.getKey().startsWith(XHTMLWikiPrinter.TRANSLATED_ATTRIBUTE_PREFIX)) {
+                    newKey = entry.getKey().substring(XHTMLWikiPrinter.TRANSLATED_ATTRIBUTE_PREFIX.length());
+                } else {
+                    newKey = entry.getKey();
+                }
+
+                result.put(newKey, entry.getValue());
+            }
+        } else {
+            result = attributes;
+        }
+
+        return result;
+    }
 }

programming_language: Java
filename: XHTMLChainingRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -41,6 +41,7 @@
 import org.xwiki.rendering.syntax.Syntax;
 import org.xwiki.rendering.syntax.SyntaxType;
 import org.xwiki.xml.html.HTMLConstants;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Convert listener events to XHTML.
@@ -65,24 +66,28 @@ public class XHTMLChainingRenderer extends AbstractChainingPrintRenderer
 
     private XHTMLImageRenderer imageRenderer;
 
+    private final HTMLElementSanitizer htmlElementSanitizer;
+
     private XHTMLWikiPrinter xhtmlWikiPrinter;
 
     /**
-     * @param linkRenderer the object to render link events into XHTML. This is done so that it's pluggable because link
-     *            rendering depends on how the underlying system wants to handle it. For example for XWiki we check if
-     *            the document exists, we get the document URL, etc.
-     * @param imageRenderer the object to render image events into XHTML. This is done so that it's pluggable because
-     *            image rendering depends on how the underlying system wants to handle it. For example for XWiki we
-     *            check if the image exists as a document attachments, we get its URL, etc.
+     * @param linkRenderer the object to render link events into XHTML. This is done so that it's pluggable because
+     *     link rendering depends on how the underlying system wants to handle it. For example for XWiki we check if the
+     *     document exists, we get the document URL, etc.
+     * @param imageRenderer the object to render image events into XHTML. This is done so that it's pluggable
+     *     because image rendering depends on how the underlying system wants to handle it. For example for XWiki we
+     *     check if the image exists as a document attachments, we get its URL, etc.
+     * @param htmlElementSanitizer the sanitizer for XHTML elements
      * @param listenerChain the chain of listener filters used to compute various states
      */
     public XHTMLChainingRenderer(XHTMLLinkRenderer linkRenderer, XHTMLImageRenderer imageRenderer,
-        ListenerChain listenerChain)
+        HTMLElementSanitizer htmlElementSanitizer, ListenerChain listenerChain)
     {
         setListenerChain(listenerChain);
 
         this.linkRenderer = linkRenderer;
         this.imageRenderer = imageRenderer;
+        this.htmlElementSanitizer = htmlElementSanitizer;
     }
 
     // State
@@ -121,11 +126,16 @@ protected void popPrinter()
     protected XHTMLWikiPrinter getXHTMLWikiPrinter()
     {
         if (this.xhtmlWikiPrinter == null) {
-            this.xhtmlWikiPrinter = new XHTMLWikiPrinter(getPrinter());
+            this.xhtmlWikiPrinter = new XHTMLWikiPrinter(getPrinter(), getHtmlElementSanitizer());
         }
         return this.xhtmlWikiPrinter;
     }
 
+    protected HTMLElementSanitizer getHtmlElementSanitizer()
+    {
+        return this.htmlElementSanitizer;
+    }
+
     // Events
 
     @Override

programming_language: Java
filename: XHTMLRenderer.java
change_type: ModificationType.MODIFY
diff: @@ -34,6 +34,7 @@
 import org.xwiki.rendering.listener.chaining.ListenerChain;
 import org.xwiki.rendering.listener.chaining.MetaDataStateChainingListener;
 import org.xwiki.rendering.renderer.AbstractChainingPrintRenderer;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Generates XHTML from a {@link org.xwiki.rendering.block.XDOM} object being traversed.
@@ -62,6 +63,9 @@ public class XHTMLRenderer extends AbstractChainingPrintRenderer implements Init
     @Inject
     private XHTMLImageRenderer imageRenderer;
 
+    @Inject
+    private HTMLElementSanitizer htmlElementSanitizer;
+
     @Override
     public void initialize() throws InitializationException
     {
@@ -74,6 +78,7 @@ public void initialize() throws InitializationException
         chain.addListener(new BlockStateChainingListener(chain));
         chain.addListener(new EmptyBlockChainingListener(chain));
         chain.addListener(new MetaDataStateChainingListener(chain));
-        chain.addListener(new XHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, chain));
+        chain.addListener(new XHTMLChainingRenderer(this.linkRenderer, this.imageRenderer, this.htmlElementSanitizer,
+            chain));
     }
 }

programming_language: Java
filename: XHTMLChainingRendererTest.java
change_type: ModificationType.MODIFY
diff: @@ -44,7 +44,7 @@
     @Test
     void outputFigureCaptionEvents()
     {
-        XHTMLChainingRenderer renderer = new XHTMLChainingRenderer(null, null, new ListenerChain());
+        XHTMLChainingRenderer renderer = new XHTMLChainingRenderer(null, null, null, new ListenerChain());
         WikiPrinter wikiPrinter = new DefaultWikiPrinter();
         renderer.setPrinter(wikiPrinter);
         renderer.beginFigureCaption(Collections.emptyMap());
@@ -57,7 +57,7 @@ void outputFigureCaptionEvents()
     @Test
     void onRawText()
     {
-        XHTMLChainingRenderer renderer = new XHTMLChainingRenderer(null, null, new ListenerChain());
+        XHTMLChainingRenderer renderer = new XHTMLChainingRenderer(null, null, null, new ListenerChain());
         WikiPrinter wikiPrinter = new DefaultWikiPrinter();
         renderer.setPrinter(wikiPrinter);
         renderer.onRawText("xhtml/1.0", Syntax.XHTML_1_0);

programming_language: Java
filename: monospace2.inout.txt
change_type: ModificationType.MODIFY
diff: @@ -1 +1 @@
-<p><tt><span a="b">monospace</span></tt></p>
\ No newline at end of file
+<p><tt><span data-xwiki-translated-attribute-a="b">monospace</span></tt></p>
\ No newline at end of file

programming_language: SQL
filename: bold4.test
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,7 @@
 .input|xhtml/1.0
 .# Verify that STRONG tag parameters are recognized.
 .#-----------------------------------------------------
-<p><strong a="b" data-xwiki-parameter="value">something</strong></p>
+<p><strong data-xwiki-translated-attribute-a="b" data-xwiki-parameter="value">something</strong></p>
 .#-----------------------------------------------------
 .expect|event/1.0
 .#-----------------------------------------------------
@@ -16,4 +16,4 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p><strong><span a="b" data-xwiki-parameter="value">something</span></strong></p>
\ No newline at end of file
+<p><strong><span data-xwiki-translated-attribute-a="b" data-xwiki-parameter="value">something</span></strong></p>
\ No newline at end of file

programming_language: Lua
filename: encoding1.test
change_type: ModificationType.MODIFY
diff: @@ -3,7 +3,7 @@
 .# Verify that HTML entities can be parsed by the XHTML parser and are encoded properly
 .# Note that &nbsp; is transformed into a space.
 .#-------------------------------------------------------------------------------------
-<p>&nbsp;&tilde;&euro;</p><p param1="val&#252;e">&#160;&#732;&#8364;</p>
+<p>&nbsp;&tilde;&euro;</p><p data-xwiki-translated-attribute-param1="val&#252;e">&#160;&#732;&#8364;</p>
 .#-----------------------------------------------------
 .expect|event/1.0
 .#-----------------------------------------------------
@@ -20,4 +20,4 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<p>&nbsp;˜€</p><p param1="valüe">&nbsp;˜€</p>
\ No newline at end of file
+<p>&nbsp;˜€</p><p data-xwiki-translated-attribute-param1="valüe">&nbsp;˜€</p>
\ No newline at end of file

programming_language: SQL
filename: group1.test
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,7 @@
 .input|xhtml/1.0
 .# Verify that div tag parameters, also starting with data-xwiki-, are recognized.
 .#-----------------------------------------------------
-<div a="b" data-xwiki-parameter="value">something</div>
+<div data-xwiki-translated-attribute-a="b" data-xwiki-parameter="value">something</div>
 .#-----------------------------------------------------
 .expect|event/1.0
 .#-----------------------------------------------------
@@ -16,4 +16,4 @@ endDocument
 .#-----------------------------------------------------
 .expect|xhtml/1.0
 .#-----------------------------------------------------
-<div a="b" data-xwiki-parameter="value"><p>something</p></div>
\ No newline at end of file
+<div data-xwiki-translated-attribute-a="b" data-xwiki-parameter="value"><p>something</p></div>
\ No newline at end of file

programming_language: Lua
filename: monospace2.inout.txt
change_type: ModificationType.MODIFY
diff: @@ -1 +1 @@
-<p><span a="b" class="monospace">monospace</span></p>
\ No newline at end of file
+<p><span data-xwiki-translated-attribute-a="b" class="monospace">monospace</span></p>
\ No newline at end of file

programming_language: SQL
filename: XHTMLWikiPrinter.java
change_type: ModificationType.MODIFY
diff: @@ -19,10 +19,15 @@
  */
 package org.xwiki.rendering.renderer.printer;
 
+import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import org.apache.commons.lang3.StringUtils;
 import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xwiki.stability.Unstable;
+import org.xwiki.xml.html.HTMLElementSanitizer;
 
 /**
  * Base toolkit class for all XHTML-based renderers. This printer handles whitespaces so that it prints "&nbsp;" when
@@ -34,6 +39,21 @@
  */
 public class XHTMLWikiPrinter extends XMLWikiPrinter
 {
+    /**
+     * Prefix that is used for invalid/disallowed attributes.
+     *
+     * @since 14.6RC1
+     */
+    @Unstable
+    public static final String TRANSLATED_ATTRIBUTE_PREFIX = "data-xwiki-translated-attribute-";
+
+    /**
+     * The sanitizer used to restrict allowed elements and attributes, can be null (no restrictions).
+     *
+     * @since 14.6RC1
+     */
+    protected final HTMLElementSanitizer htmlElementSanitizer;
+
     private int spaceCount;
 
     private boolean isInCData;
@@ -50,15 +70,25 @@ public class XHTMLWikiPrinter extends XMLWikiPrinter
      * @param printer the object to which to write the XHTML output to
      */
     public XHTMLWikiPrinter(WikiPrinter printer)
+    {
+        this(printer, null);
+    }
+
+    /**
+     * @param printer the object to which to write the XHTML output to
+     * @param htmlElementSanitizer the sanitizer to use for sanitizing elements and attributes
+     */
+    public XHTMLWikiPrinter(WikiPrinter printer, HTMLElementSanitizer htmlElementSanitizer)
     {
         super(printer);
+        this.htmlElementSanitizer = htmlElementSanitizer;
     }
 
     /**
-     * Use it to specify that the current element to print is standalone.
-     * This value might be used to know if the first space should be printed with a simple space or a {@code &nbsp;}
-     * entity. Note that the standalone value is automatically reset after first printing of a space, or when a text
-     * is printed.
+     * Use it to specify that the current element to print is standalone. This value might be used to know if the first
+     * space should be printed with a simple space or a {@code &nbsp;} entity. Note that the standalone value is
+     * automatically reset after first printing of a space, or when a text is printed.
+     *
      * @since 12.2
      */
     public void setStandalone()
@@ -78,58 +108,74 @@ public void printXML(String str)
     @Override
     public void printXMLElement(String name)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLElement(name);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLElement(name);
+        }
     }
 
     @Override
     public void printXMLElement(String name, String[][] attributes)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLElement(name, attributes);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLElement(name, cleanAttributes(name, attributes));
+        }
     }
 
     @Override
     public void printXMLElement(String name, Map<String, String> attributes)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLElement(name, attributes);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLElement(name, cleanAttributes(name, attributes));
+        }
     }
 
     @Override
     public void printXMLStartElement(String name)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLStartElement(name);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLStartElement(name);
+        }
     }
 
     @Override
     public void printXMLStartElement(String name, String[][] attributes)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLStartElement(name, attributes);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLStartElement(name, cleanAttributes(name, attributes));
+        }
     }
 
     @Override
     public void printXMLStartElement(String name, Map<String, String> attributes)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLStartElement(name, attributes);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLStartElement(name, cleanAttributes(name, attributes));
+        }
     }
 
     @Override
     public void printXMLStartElement(String name, Attributes attributes)
     {
-        handleSpaceWhenStartElement();
-        super.printXMLStartElement(name, attributes);
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenStartElement();
+            super.printXMLStartElement(name, cleanAttributes(name, attributes));
+        }
     }
 
     @Override
     public void printXMLEndElement(String name)
     {
-        handleSpaceWhenEndlement();
-        super.printXMLEndElement(name);
-        this.elementEnded = true;
+        if (this.htmlElementSanitizer == null || this.htmlElementSanitizer.isElementAllowed(name)) {
+            handleSpaceWhenEndlement();
+            super.printXMLEndElement(name);
+            this.elementEnded = true;
+        }
     }
 
     @Override
@@ -185,6 +231,71 @@ private void handleSpaceWhenInText()
         }
     }
 
+    private Map<String, String> cleanAttributes(String elementName, Map<String, String> attributes)
+    {
+        Map<String, String> cleanAttributes;
+
+        if (this.htmlElementSanitizer == null || attributes == null) {
+            cleanAttributes = attributes;
+        } else {
+            cleanAttributes = new LinkedHashMap<>();
+            for (Map.Entry<String, String> e : attributes.entrySet()) {
+                if (this.htmlElementSanitizer.isAttributeAllowed(elementName, e.getKey(), e.getValue())) {
+                    cleanAttributes.put(e.getKey(), e.getValue());
+                } else {
+                    cleanAttributes.put(TRANSLATED_ATTRIBUTE_PREFIX + e.getKey(), e.getValue());
+                }
+            }
+        }
+
+        return cleanAttributes;
+    }
+
+    private String[][] cleanAttributes(String elementName, String[][] attributes)
+    {
+        String[][] allowedAttributes;
+        if (this.htmlElementSanitizer == null || attributes == null) {
+            allowedAttributes = attributes;
+        } else {
+            allowedAttributes = Arrays.stream(attributes)
+                .map(entry -> {
+                    if (this.htmlElementSanitizer.isAttributeAllowed(elementName, entry[0], entry[1])) {
+                        return entry;
+                    } else {
+                        return new String[] { TRANSLATED_ATTRIBUTE_PREFIX + entry[0], entry[1] };
+                    }
+                })
+                .toArray(String[][]::new);
+        }
+
+        return allowedAttributes;
+    }
+
+    private Attributes cleanAttributes(String elementName, Attributes attributes)
+    {
+        Attributes allowedAttribute;
+
+        if (this.htmlElementSanitizer == null || attributes == null) {
+            allowedAttribute = attributes;
+        } else {
+            allowedAttribute = new AttributesImpl();
+
+            for (int i = 0; i < attributes.getLength(); ++i) {
+                if (this.htmlElementSanitizer.isAttributeAllowed(elementName, attributes.getQName(i),
+                    attributes.getValue(i)))
+                {
+                    ((AttributesImpl) allowedAttribute).addAttribute(null, null, attributes.getQName(i),
+                        null, attributes.getValue(i));
+                } else {
+                    ((AttributesImpl) allowedAttribute).addAttribute(null, null,
+                        TRANSLATED_ATTRIBUTE_PREFIX + attributes.getQName(i), null, attributes.getValue(i));
+                }
+            }
+        }
+
+        return allowedAttribute;
+    }
+
     private void handleSpaceWhenStartElement()
     {
         // Use case: <tag1>something <tag2>...

programming_language: Java