Security Research LaboratoryWhere is this place located?

Log in to follow, share, and participate in this community. Not a member? Join Now!


Coverity Security Blog - Latest Posts

Refresh this widget

We've decided to move our blogging platform onto a new site that we've been working on for a while:  Thanks for reading, and enjoy the new site!






(Note: this write-up uses the Maven sample application provided by Struts2. Refer to the Appendix section at the bottom to install the application. References to the blank-archetype application refer to this sample application.)

From the Struts 2 website

Apache Struts 2 is an elegant, extensible framework for creating enterprise-ready Java web applications. The framework is designed to streamline the full development cycle, from building, to deploying, to maintaining applications over time.

Struts 2 heavily utilizes OGNL as a templating / expression language. OGNL, similar to other expression languages, is vulnerable to a class of issues informally termed "double evaluation". That is, the value of an OGNL expression is mistakenly evaluated again as an OGNL expression. For a background on previous OGNL double evaluation issues, I recommend @meder's "Milking a horse or executing remote code in modern Java frameworks" presentation. (The exploit used below is based on @meder's exploit, just condensed.) For other examples of double evaluation in different expression languages, check out Aspect Security's "Remote Code with Expression Language".


Struts 2 calls its controllers Actions. Actions are mapped to URLs and views within an XML configuration file or via Java annotations. For a good background on Struts 2 and Actions, refer to their "Getting Started" page.


Struts 2 allows a developer to configure wildcard mappings in its XML configuration files. The blank-archetype application has the following wildcard example in its XML configuration:


<action name="*" class="tutorial2.example.ExampleSupport">


This allows one to specify an arbitrary Action name. If the name doesn't match any of the other more specific mappings in the XML configuration (or possibly others annotated in the Java code), then this acts as a catch-all. The Action name provided is substituted as a component of the file name. Struts then dispatches to the selfsame JSP defined in the result section.


Vulnerability and Exploit

There exists a vulnerability in this Action name to replacement mapping. If the Action name provided is in the form of ${STUFF_HERE} or %{STUFF_HERE}, and the contents of the expression are OGNL, then Struts2 unsafely double evaluates the contents.

To view this exploit, start up the blank-archetype application using jetty:run. The following URL exploits a vulnerability within the replacement support in Struts 2. If the exploit is successful, something similar to the following should be displayed:


Problem accessing /struts2-blank/example/0.jsp. Reason:

Not Found

Note the "0.jsp" part in the 404 page. When successfully executed, Process.waitFor returns a value of "0". This is then used as the JSP file name, "0.jsp". This implies the touch aaa executed successfully. A patched version doesn't have a return value since the process never executed.


Root Cause Analysis

Using JavaSnoop, instrumenting the blank-archetype application application, and setting canaries for strings to match against the payload URL showed numerous potential traces. Scoping the trace to org.apache.struts2 packages shows an interesting call to StrutsResultSupport.conditionalParse:


* Parses the parameter for OGNL expressions against the valuestack
* @param param The parameter value
* @param invocation The action invocation instance
* @return The resulting string
protected String conditionalParse(String param, ActionInvocation invocation) {
    if (parse && param != null && invocation != null) {
        return TextParseUtil.translateVariables(param, invocation.getStack(),
                new TextParseUtil.ParsedValueEvaluator() {
                    public Object evaluate(String parsedValue) {
                        if (encode) {
                            if (parsedValue != null) {
                                try {
                                    // use UTF-8 as this is the recommended encoding by W3C to
                                    // avoid incompatibilities.
                                    return URLEncoder.encode(parsedValue, "UTF-8");
                                catch(UnsupportedEncodingException e) {
                                    if (LOG.isWarnEnabled()) {
                                        LOG.warn("error while trying to encode ["+parsedValue+"]", e);
                        return parsedValue;
    } else {
        return param;


The method above is called from the StrutsResultSupport.execute(ActionInvocation). It then calls TextParseUtil.translateVariables:


 * Function similarly as {@link #translateVariables(char, String, ValueStack)}
 * except for the introduction of an additional <code>evaluator</code> that allows
 * the parsed value to be evaluated by the <code>evaluator</code>. The <code>evaluator</code>
 * could be null, if it is it will just be skipped as if it is just calling
 * {@link #translateVariables(char, String, ValueStack)}.
 * <p/>
 * A typical use-case would be when we need to URL Encode the parsed value. To do so
 * we could just supply a URLEncodingEvaluator for example.
 * @param expression
 * @param stack
 * @param evaluator The parsed Value evaluator (could be null).
 * @return the parsed (and possibly evaluated) variable String.
public static String translateVariables(String expression, ValueStack stack, ParsedValueEvaluator evaluator) {
  return translateVariables(new char[]{'$', '%'}, expression, stack, String.class, evaluator).toString();


This method evaluates expressions surrounded with ${} or %{}. The subsequent call to translateVariables method evaluates the expression via the parser.evaluate call:


 * Converted object from variable translation.
 * @param open
 * @param expression
 * @param stack
 * @param asType
 * @param evaluator
 * @return Converted object from variable translation.
public static Object translateVariables(char[] openChars, String expression, final ValueStack stack, final Class asType, final ParsedValueEvaluator evaluator, int maxLoopCount) {
    ParsedValueEvaluator ognlEval = new ParsedValueEvaluator() {
        public Object evaluate(String parsedValue) {
            Object o = stack.findValue(parsedValue, asType);
            if (evaluator != null && o != null) {
                o = evaluator.evaluate(o.toString());
            return o;
    TextParser parser = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(TextParser.class);
    XWorkConverter conv = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(XWorkConverter.class);
    Object result = parser.evaluate(openChars, expression, ognlEval, maxLoopCount);
    return conv.convertValue(stack.getContext(), result, asType);


That passes the expression to an instance of OgnlTextParser.evaluate. And then it's game over.


Other Vectors

Suspicious calls to TextParseUtil.translateVariables were also examined for exploitability.


org.apache.struts2.dispatcher.HttpHeaderResult.execute (Tested)

HttpHeaderResult.execute has the following call to TextParseUtil.translateVariables:


if (headers != null) {
    for (Map.Entry<String, String> entry : headers.entrySet()) {
        String value = entry.getValue();
        String finalValue = parse ? TextParseUtil.translateVariables(value, stack) : value;
        response.addHeader(entry.getKey(), finalValue);


The blank-archetype application's HelloWorld XML example was modified below to test out the call. This is probably a very unlikely scenario and also can be mitigated by the <param name="parse">false</param> setting. (By default, this value is true.) In this case, the ${message} value is user-controllable within the HelloWorld class. This tainted value is then supplied as a header. While it's an obvious header injection, it's also a RCE vector.


<action name="HelloWorld" class="com.coverity.internal.examples.example.HelloWorld">
  <result name="success">/example/HelloWorld.jsp</result>
  <result name="foobar" type="httpheader">
    <param name="headers.foobar">${message}</param>


org.apache.struts2.views.util.DefaultUrlHelper.* (Tested)

Pretty much every method in the DefaultUrlHelper class allows for RCE if one of the parameters is tainted. This is because of the DefaultUrlHelper.translateVariable method is called by most methods in the class. This class is also heavily utilized throughout Struts2 as the default UrlHelper class via struts-default.xml.


Here is an instance of the defect, mocked up from the blank-archetype application HelloWorld.jsp:


<s:url id="url" action="HelloWorld">
    <s:param name="request_locale"><s:property value="message"/></s:param>


Assume the s:property 'message' is tainted via ?message=${OGNL_HERE}. Since the s:url / URL component uses the DefaultUrlHandler.urlRenderer (via ServletUrlRenderer), the parameter is double evaluated as OGNL.


org.apache.struts2.util.URLBean.getURL (Untested)

URLBean seems to mainly be used in Velocity via a macro. If URLBean is called w/o a setPage() method and either the addParameter() method contains tainted data or no addParameter() method calls occur, then URLBean seems susceptible to RCE via the DefaultUrlHelper issue above.



Some potential vectors that seemed to double evaluate OGNL were tested but found not to be exploitable using this technique.

When the action name is used as a replacement value within the method attribute of the Action, the replacement value is not double evaluated. Rather, the unevaluated value is passed as a method name via reflection. The blank-archetype application has this example, which is not exploitable:


<action name="Login_*" method="{1}" class="tutorial.example.Login">
  <result name="input">/example/Login.jsp</result>
  <result type="redirectAction">Menu</result>


Another non-vector tested in the blank-archetype application is to enable Dynamic Method Invocation. Then modify HelloWorld Action mapping in the blank-archetype application as follows:


<action name="HelloWorld" class="tutorial.example.HelloWorld">


Finally, call the getMessage function on the HelloWorld Action (HelloWorld!getMessage?message=${PAYLOAD}). Test stack traces didn't show the OGNL expression being evaluated twice.



Struts2 annotations may be susceptible but have not been tested.



Outside of testing for vulnerable versions of Struts 2, testers can use a blind-ish dynamic technique:

  • Identify Actions (usually via a .action suffix) and fingerprint responses to the Actions. For this example URL, the Action name is Bar.
  • For each Action, substitute the Action name  with ACTION_NAME in the following expression: $%7B%23foo='ACTION_NAME',%23foo%7D. For example: $%7B%23foo='Bar',%23foo%7D.
  • Replace the Action name in the URL with the substituted expression. For example:$%7B%23foo='Bar',%23foo%7D.action.
  • If the Action is susceptible to this double evaluation vector, the application ought to return the same page as before. If it's not vulnerable, a 404 or other page will probably be returned.

To test out the Welcome.action blank-archetype above via jetty:run, use this URL.



Struts developers recommend upgrading to Refer to S2-013 and S2-014 for details. The Struts developers mitigate the effects of double evaluation. While double evaluation still occurs within the sample application, remote code execution is not possible using @meder's vector.


Maven Appendix

First, get Maven. Then create an application based on the blank-archetype.


mvn archetype:generate -B -DgroupId=tutorial -DartifactId=tutorial -DarchetypeGroupId=org.apache.struts -DarchetypeArtifactId=struts2-archetype-blank
cd tutorial  # ensure the struts2 entry in the pom.xml points to 2.3.14
mvn package jetty:run


To test out the application, try accessing the Welcome Action by navigating to following URL.

As part of our work at Coverity, the Security Research Laboratory (SRL) performs security reviews of our own software. Last week I had a look at some of the new code in our reporting webapp. It turned out that we were using some technologies and vulnerable code patterns I had not seen before, so I thought I would share what I saw with the world in case anyone sees the same pattern I did.


As I began to review this code for the first time, I identified a series of Closure Templates that were being used to generate HTML output, with the usual {$} syntax being used to insert model values into the output. After a little bit of looking around, I saw that they hadn't changed Closure's default escaping away from HTML escaping, and they were also not putting these properties into any contexts where HTML escaping was incorrect.

However, I also noticed that there was a lot of syntax similar to {literal}{{}}{/literal} and many HTML attributes such as ng-repeat that I hadn't seen before.


Somewhat confused by this, I dug a bit further and discovered that rather than being directly displayed, the output of these views was being passed to a JavaScript framework called Angular.


If you are like me and have never heard of Angular before, it seems to be a complete MVC framework for JavaScript and it turned out that our HTML output was actually being used as the views for Angular.


Like most server-side MVC, most of the view in Angular is plain old HTML. Angular augments this by a series of directives that are specified as attributes (e.g., the ng-repeat attribute I had seen) and the ability to bind data into attributes or right into HTML as Angular expressions. So the {literal}{{}}{/literal} I was seeing in our Closure Templates was being output as {{}} and being consumed by Angular, which was binding the values from its own model in there.


So, in my eternal quest for more XSS, I went to investigate what would happen if a user was able to inject {{}} expressions into an Angular template. I was convinced that this would let me XSS our application somehow.


After digging a bit, it turns out that Angular doesn't simply eval() these expressions, but rather has its own expression tokenizer/evaluator written in JavaScript.


The things that this evaluator supports are:

  • Model access: {{modelVar}}
  • Field access: {{modelVar.field}}
  • Function calls: {{modelVar.function(1)}}
  • Built-in filter functions: {{ modelVar | json }}
  • Arithmetic and logical operators: {{1+2}}, {{true&&false}}, etc.
  • Object and Array constructors: {{ {name: 'test'} }}


The first thing I tried was to find a filter function that would allow me to somehow execute JavaScript, but after reviewing the built-in filter functions as well as the ones our application injected, I determined this wasn't going to work.


One of the filters our application created was called autoescape, which did some HTML escaping and was being applied to some data like {{tts.get('id')|autoescape}} which made me wonder if I could have my XSS by creating an expression that would return <script>alert(1)</script> without using any characters that would be encoded on the server side. Using this JsFiddle to test what would happen if I could I could get an expression that returned an XSS string, I realized that this too was a dead end for my XSS dreams.


So I decided to review the expression parser to see what was going on in there, and if anything looked sketchy. I discovered that the underlying objects that Angular was using in its expressions were native JavaScript objects (rather than providing their own custom object model, which some view technologies do); so field access was implemented by simply accessing the native fields of an object. This was interesting because besides properties you assign to an object, native objects will have several other fields attached.


After staring at the MDN for a bit, I discovered the same thing that many before me had discovered:

{}.toString.constructor('alert(1)') creates a new function from a string by invoking the Function constructor.


So to wrap this all up, if you can inject {{}} into an angular template, the following will execute JavaScript when data values are bound into the template:


And now our developers have one more XSS to fix before the code ships to our customers. If you'd like to play around with it yourself, I've set-up another jsFiddle with the payload already working.

Update March 1st: Since the PDF on RSA website seems broken, I have attached a version to this blog post.



I'll be at RSA this week. My session is Friday morning (10:20am, Room 132) and is called:

Why haven't we stamped out XSS and SQL yet?


RSA talk content

Since all the slides are apparently available for everyone on the RSA website, I can give some more insight about what I will be talking about. We ran an experiment at Coverity in which we analyzed many Java web applications and looked for where developers add dynamic data. The goal was to try to understand what contexts (both HTML contexts and SQL contexts) are frequently used.


The tone of the talk is fairly straightforward: security pros. have been giving advice to developers for a long time, yet we still have these issues on a frequent basis, so we map common advice with what we see from the data.


What you can expect from this talk:

  • Some information about observed HTML contexts: that's about 26 different contexts stacks, 45% of them had 2 elements in the stack (e.g., HTML attribute -> CSS code), and the longest ones had 3 elements.
  • A list of SQL contexts and good notes about what developers usually do.
  • Advice for security pros. on how to communicate with developers (things that led to the creation of our Fixing XSS: A practical guide for developers document).


Anyhow, this blog post is not only to announce this talk, but also to give some insight on how we extracted the data from these applications.


Analysis technique

We created and modified different checkers from Coverity Security Advisor in order to extract all injection sites that are related to dynamic data regardless of its taintedness. For each injection site, we computed the context in which it belonged to the sub language (one of HTML, JavaScript, CSS, SQL, HQL, and JQPL). This represents our working dataset.


Here's an example of an injection site (using JSP and EL):

<script type="text/javascript">
var content = '${dynamic_data}';
// context ::= {HTML SCRIPT TAG -> JS STRING}


We tracked the construction of this snippet of the HTML page and recorded the injection site such as ${dynamic_data} and its associated context (JS STRING inside HTML SCRIPT TAG). Since we do not care about the taintedness of dynamic_data, we didn't need to track all paths that could lead to a defect (XSS here), and that's where what we did is very different from our XSS checker.

Note that we still needed to properly track parts of the HTML page that's being constructed to properly compute the context. This is however part of our context-aware global data flow analysis...


For SQL related queries, we essentially needed to do the same thing, but we also needed to track the parameters being inserted in a query using a parameterized notation: remember, we needed to find all dynamic data that could eventually go into a query.

That's why the following code:

String sql = "select foo, bar from table where 1=1";
if (cond1)
  sql += " and user='" + user_name + "'"; // context ::= {SQL_STRING}
if (cond2)
  sql += " and password=?"; // context ::= {SQL_DATA_VALUE}

has 2 interesting injection sites for the experiment, and we didn't need to understand the full abstract string (an eventual set of 4 possible strings) from this piece of code.


Note that if there is this fairly common construct:

String sql1 = "select foo, bar from table where ";
String and_beg = " and (";
String and_end = " ) ";
sql1 += and_beg + "user = '" + user_name + "'" + and_end;
sql1 += sql2; // `sql2` is another part of the query coming
              // from a different procedure or so

we will still properly track the contexts even if all parts (sql1, and_beg, etc.) are inter-procedurally created.



I will quickly explain this during the talk, but essentially tracking HTML contexts on a global data flow analysis is not a trivial thing. Moreover, considering the impact of some JavaScript code on the resulting web page (and therefore where the HTML contexts could potentially be transformed at runtime) is an even more complex problem. We did not analyze JavaScript.

I'm happy to announce a new document we just made available: Fixing XSS: a practical guide for developers. If you're currently at the RSA conference, you should come to Coverity's booth (#1759) and either get a hardcopy or a USB stick with this document on it.


As the title suggests, this document is a guide for developers on how to handle dynamic data in various locations and common constructs in HTML. We leveraged the data we got from our research for our talk at RSA to come up with some of the most common HTML contexts and nested contexts, and improved the Coverity Security Library to have a solution for all of these cases.


Looking at the documentation available for XSS, several things strike us:

  1. It often talks about how to exploit an XSS and not how to fix this issue.
  2. The HTML contexts information is always lacking precision and often makes the documentation complex to read (we're also guilty of this in some previous blog posts).
  3. The fixes are limited or too restrictive (i.e., not applicable for developers).

That's mostly why we decided to create our own document for developers.


The first release of this document contains 13 common HTML constructs, and we plan on adding more to it. We also describe what HTML contexts are and why it's important to think about them when outputting dynamic data in a web page. However, we also want to create collateral that gives more complete information about HTML contexts and why it matters for XSS.


In this document, you can expect to learn what happens when you want to add dynamic data in a HTML context such as HTML snippet inside a JavaScript string:

<div id="forMyContent"></div>
  var foo = "<h1>${cov:jsStringEscape(cov:htmlEscape(content))}</h1>";

and why you need to first use an HTML escaper, then a JavaScript string escaper.


You'll also see the usage of a newly introduced function asUrl from CSL that helps writing fully dynamic URLs inside an HTML attribute such as:

<a href="${cov:htmlEscape(cov:asURL(content))}">
  Click me


The current document uses the Java Expression Language (EL) notation to show the dynamic data (here ${content}), but all functions are also available directly from Java when using CSL.


Whether you develop web applications, have developers, or do security review, you should read and share this document. We're also happy to receive any feedback to keep improving this document.

Featured Team Members

Latest Poll

Refresh this widget

No polls yet