diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php
index 5cbf2712f7..7719ce5afa 100644
--- a/phpBB/phpbb/textformatter/s9e/factory.php
+++ b/phpBB/phpbb/textformatter/s9e/factory.php
@@ -311,7 +311,7 @@ class factory implements \phpbb\textformatter\cache_interface
{
$configurator->Emoticons->set(
$row['code'],
- '
'
+ '
'
);
}
@@ -441,6 +441,20 @@ class factory implements \phpbb\textformatter\cache_interface
->addParameterByName('parser');
}
+ /**
+ * Escape a literal to be used in an HTML attribute in an XSL template
+ *
+ * Escapes "HTML special chars" for obvious reasons and curly braces to avoid them
+ * being interpreted as an attribute value template
+ *
+ * @param string $value Original string
+ * @return string Escaped string
+ */
+ protected function escape_html_attribute($value)
+ {
+ return htmlspecialchars(strtr($value, ['{' => '{{', '}' => '}}']), ENT_COMPAT | ENT_XML1, 'UTF-8');
+ }
+
/**
* Return the default BBCodes configuration
*
diff --git a/tests/text_processing/tickets_data/PHPBB3-15163.html b/tests/text_processing/tickets_data/PHPBB3-15163.html
new file mode 100644
index 0000000000..a1af10187c
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15163.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15163.txt b/tests/text_processing/tickets_data/PHPBB3-15163.txt
new file mode 100644
index 0000000000..126402d66a
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15163.txt
@@ -0,0 +1 @@
+--{E
\ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15163.xml b/tests/text_processing/tickets_data/PHPBB3-15163.xml
new file mode 100644
index 0000000000..f3e04c230f
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15163.xml
@@ -0,0 +1,23 @@
+
+
+
+ smiley_id
+ code
+ emotion
+ smiley_url
+ smiley_width
+ smiley_height
+ smiley_order
+ display_on_posting
+
+ 1
+ --{E
+ --{E
+ icon_lol.gif
+ 15
+ 17
+ 22
+ 1
+
+
+