Last updated Dec 23, 2024

JIRA 6.0 - HTML escaping for velocity templates

Html Encoding

  • Rendering data from untrusted sources in Velocity templates can result in XSS vulnerabilities if the data has not been html encoded.
  • As of JIRA 5.1, we have introduced the ability to opt into automatic HTML escaping for all references
  • For the JIRA 6.0 release, we will enable automatic HTML escaping by default for all template files, and plugin developers will have to explicitly opt out of HTML escaping to preserve 5.1 behaviour.
  • Plugin developers are able to explicitly opt out (or in) to automatic HTML escaping, so that their templates behave the same in 5.x releases and 6.0.

Introduction

This documentation is aimed at JIRA plugin developers with detailed instructions on how to update their plugins to take advantage of the new html escaping facilities provided for velocity templates in JIRA 5.1

In general, as of JIRA 5.1 if automatic html escaping has been enabled for a velocity template, the result of evaluating references and method calls in the template will be escaped before being written into the html response unless the result has been explicitly designated as containing html encoded content.

For now, it is necessary to opt-in to automatic escaping for it to applied to an specific template. However, we intend to change this setting in JIRA 6.0 so that it is applied to all templates unless the developer explicitly opts-out of it for the template to be rendered.

Consequently, it is recommended that you adjust your template files by explicitly turning off or on automatic escaping in each of them,  in order to prepare your plugin for this change before JIRA 6.0 is released.

Enabling Automatic Html Escaping

To enable escaping for a template file it is only necessary to add the following directive to your template file:

1
2
#enable_html_escaping()
...

Local Macros

Local macros are evaluated according to the escaping directive set on the template.

For instance, given the following macro definition:

1
2
#macro( test )
    <span>
        $action.getContent()
    </span>
#end

and the following template fragment:

1
2
#enable_html_escaping()
...
    <div>
        <span>Macro Content:</span>
        #test()
    </div>
....

The result of invoking action.getContent will be html escaped.

Parsed Templates

Parsed templates are also evaluated according to the escaping directive set on the template embedding them.

For instance, given the following template fragment in a file named /templates/includes/basic-fragment.vm

1
2
<span id="fragment-for-inclusion">
    $action.getContent()
</span>

and the following template fragment:

1
2
#enable_html_escaping()
...
    <div>
        <span>Parsed Content:</span>
        #parse("/templates/includes/basic-fragment.vm")
    </div>")
    </div>
....

The result of the action.getContent will be html escaped.

Consequently, if you rely on parsing to reuse common markup across the templates in your plugin, you will need to create versions of these template fragments that are ready to work with automatic escaping so that you can use embed in templates that activate the automatic html escaping directive.

Disabling Automatic Html Escaping

Template

To explicitly disable escaping at the template level, you only need to add the following directive:

1
2
#disable_html_escaping()
...

The results of evaluating references and methods in this template will not be html escaped.

As of JIRA 5.1, this is the default setting for any template file. However we strongly advise you to explicitly specify this setting in your legacy templates to prepare for the JIRA 6.0 release where automatic escaping setting will be changed to be on by default.

References

In order to avoid escaping when a specific reference is evaluated you only need to append the string "html" at the end of the reference. For instance:

Given a reference named contentAsHtml:

1
2
#enable_html_escaping()
... 
#set($contentAsHtml = "<span style='color:red;'>This should not be escaped, therefore rendering in red colour.</span>"
<div>
     <span>Disabling Escaping - References:</span>
     $contentAsHtml
</div>

Html escaping will not be applied when it is evaluated, the output will be:

This should not be escaped, therefore rendering in red colour.

Methods

In order to avoid escaping when a specific method call is evaluated you only need to append the string "html" at the end of the method's name, or alternatively, annotate the method as @HtmlSafe.

Html Suffix

Given a method named getFragmentHtml:

1
2
...   
 public String getFragmentHtml()
    {
        return "<span style='color:blue'>" +
                    "This method call should not be escaped, therefore rendering in blue colour" +
                "</span>";
    }
...

and a template fragment:

1
2
#enable_html_escaping()
... 
    <div>
        <span>Disabling Escaping - Methods Via Naming:</span>
        $action.getFragmentHtml()
    </div>

Html escaping will not be applied when it the method call is evaluated. The output will be:

This method call should not be escaped, therefore rendering in blue colour

@HtmlSafe Annotation

Given the following method definition:

1
2
...
@HtmlSafe
public String getFragment()
{
    return "<span style='color:grey'>" +
            "This method call should not be escaped, therefore rendering in grey colour" +
            "</span>";
}
...

and a template fragment:

1
2
#enable_html_escaping()
... 
    <div>
        <span>Disabling Escaping - Methods Via Annotation:</span>
        $action.getFragment()
    </div>
...

Html escaping will not be applied when the method call is evaluated. The output will be:

This method call should not be escaped, therefore rendering in grey colour

The annotation is in the com.atlassian.velocity.htmlsafe package included in the velocity-htmlsafe library. To use it from your plugin, you need the following dependency declaration to your pom.xml

1
2
...        
<dependency>
    <groupId>com.atlassian.velocity.htmlsafe</groupId>
    <artifactId>velocity-htmlsafe</artifactId>
    <version>1.1.1</version>
    <scope>provided</scope>
</dependency>
...

Defaults

Methods

In order to aid in the migration of legacy templates, the following list of library methods are not escaped by convention when evaluated inside a template:

  • com.opensymphony.util.TextUtils.htmlEncode
  • org.apache.velocity.tools.generic.EscapeTool.html
  • com.opensymphony.webwork.util.WebWorkUtil.htmlEncode
  • com.opensymphony.webwork.util.VelocityWebWorkUtil.htmlEncode

Additionally, the result of evaluating methods starting with render or getRender is not escaped either.

References

In order to aid in the migration of legacy templates, the following list of references are not escaped when evaluated

  • xHtmlContent
  • body

Additional Documentation

Confluence Automatic Html Escaping Documentation: JIRA shares the automatic escaping infrastructure used by Confluence.

JIRA Automatic Escaping Examples: This sample plugin project contains code that demonstrates all the concepts explained in this guide.

Rate this page: