7 – Does calling filter_xss() or filter_xss_admin() more than once have undesired effects?


Background

Some sanitization functions cause undesired effects if called more than once.

$str = 'a < b';
$f = 'check_plain';
$f($str) === 'a &lt; b';
$f($f($str)) === 'a &amp;lt; b';

It seems this is not the case for filter_xss_admin():

$str = 'a < b';
$f = 'filter_xss_admin';
$f($str) === 'a &lt; b';
$f($f($str)) === 'a &lt; b';

We can distinguish different categories of sanitization functions:

The only function I can think of that has both qualities is the identity function.

Question

Does filter_xss() ever further modify an already-sanitized string?

Or: Is there a string $str where filter_xss_admin($str) !== filter_xss_admin(filter_xss_admin($str))?

Use case

See https://www.drupal.org/project/drupal/issues/2408955 and https://www.drupal.org/node/2824413

Drupal 7 core prints status messages unfiltered.

The Bootstrap theme passes them through filter_xss_admin().

I work on a contrib module where I want to use this theme hook, and I want to have consistent behavior no matter which theme.

I want to find out if I need to actively prevent double-escaping.

Thoughts

The filter_xss() function contains a bunch of str_replace() and preg_replace(). I find it hard to predict whether this is reliably idempotent, but I also find it hard to come up with a counter-example.