Disabling escaping of special characters in templates is a security riskJAVA-S1025
Automatic variable escaping should not be disabled when using template processing systems such as Mustache or FreeMarker.
When special characters (such as '<', '>', or '/') are encountered, templating engines such as JMustache can automatically replace them with equivalent escape sequences. This prevents malicious inputs from inserting executable code into the final page, leading to an XSS (Cross Site Scripting) attack.
However, character escaping is context sensitive and characters that are safe to keep unescaped outside of HTML tags may not be safe to leave alone within attributes, or vice versa. In the example below, a template engine that does not escape ':'
characters has been used.
<a href="{{ myLink }}">link</a>
If myLink
's value were set to a JavaScript scheme string such as javascript:alert('hack')
, the resultant HTML could become the setup for an XSS attack:
<a href="javascript:alert('hack')">link</a>
This issue is reported when HTML escaping is disabled in the JMoustache and FreeMarker template engines.
Bad Practice
When using JMoustache, do not call escapeHTML()
with a false
value, or set the escaper to Escapers.NONE
.
Mustache
.compiler()
.escapeHTML(false) // Not good.
.withEscaper(Escapers.NONE) // Not good either.
.compile(template)
.execute(context);
When using FreeMarker, do not call Configuration.setAutoEscapingPolicy()
with DISABLE_AUTO_ESCAPING_POLICY
.
Configuration config = new Configuration();
config.setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY);
Recommended
In JMustache, auto-escaping is turned on by default; there is no need to explicitly set the behavior, but you could do so by passing true
to Compiler.escapeHTML()
, or by passing Escapers.HTML
to Compiler.withEscaper()
.
Mustache
.compiler() // Doing nothing is an option.
.escapeHTML(true) // But you can set escapeHTML to true if you want to.
.withEscaper(Escapers.HTML) // Or set the escaper to Escapers.HTML.
.compile(template)
.execute(context);
FreeMarker's auto-escaping is also turned on by default for HTML; but you can force it to be on by calling setAutoEscapingPolicy()
with the right arguments:
config.setAutoEscapingPolicy(Configuration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY); // This is the default.
config.setAutoEscapingPolicy(Configuration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY); // This is also a viable option.
References
- OWASP Top Ten (2021) - Category A03 - Injection
- OWASP Cheat Sheets - XSS Prevention
- CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')