Twig auto-escapes any string that is output using the normal notation, as follows:
{{ variable_name }}
However, there are cases in which the variable has already been marked safe, and Twig no longer escapes it. This is usually in the case of MarkupInterface objects, such as FilteredMarkup or FormattableMarkup. In these cases, Twig assumes that the strings they wrap have already been sanitized and that they can be output 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 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, throughout this book we used the t() function (and the StringTranslationTrait method) which 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 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 previous sanitization methods will prevent XSS attacks when dealing with markup that Twig doesn't escape.