Twig auto-escapes any string that is outputted using the normal notation, as follows:
{{ variable_name }}
However, there are cases in which the variable has already been marked safe, and Twig does not escape it anymore. This is usually in the case of MarkupInterface objects--such as FilteredMarkup or FormattableMarkup--we saw in Chapter 12, JavaScript and the Ajax API, when we discussed translations (extended by TranslatableMarkup). In these cases, Twig assumes that the strings they wrap have already been sanitized and that they can be outputted as they are. Of course, it is then up to us, as module developers, to ensure that we don't use any such objects with strings that contain an unsanitized user input.
Let's look at a popular example of such an object we use all the time, and then we will talk about the different ways we can sanitize our user input.
If you remember, in Chapter 12, JavaScript and the Ajax API, we talked about the t() function (and the StringTranslationTrait method) that returns a TranslatableMarkup object used for translating strings. Printing such an object inside Twig will prevent auto-escaping because Twig already considers it safe. Moreover, if you remember, this applies to the main string only, as any placeholders we use do get escaped:
$object = t('This does not get escaped but this does: @safe', ['@safe' => 'This can be unsafe as it will be escaped'])
Even if there were no security implications, we should not be passing user input or variables to TranslatableMarkup, as that hinders the actual purpose of these objects--to translate the string. However, for other MarkupInterface objects, there are a few ways we can treat user input or strings of a dubious origin in order to prepare them for Twig:
- Drupal\Component\Utility\Html::escape(): This is the strictest sanitization function used to print plain text. It uses PHP's htmlspecialchars() to convert special characters to HTML entities.
- Drupal\Component\Utility\Xss::filter(): This filters HTML to prevent XSS attacks. It also allows a few basic HTML elements.
- Drupal\Component\Utility\Xss::filterAdmin(): This is a very permissive XSS filter that allows through most HTML elements apart from things like <script> or <style>. It should be used only for known and safe sources of input.
- Drupal\Component\Utility\UrlHelper::filterBadProtocol(): This strips dangerous protocols from URLs. It should be used before printing the HTML attribute value when the URLs are obtained from user input or unsafe sources.
So, depending on the case, using one of the preceding sanitization methods will prevent XSS attacks when dealing with markup that Twig doesn't escape.