Payment Tampering Using Template Injection

Team we45
February 22, 2019
Payment Tampering Using Template Injection

The unprecedented rise in online transactions has been promptly followed by a corresponding rise in attacks on online payment handling systems. This piece has been written in recognition of the prevalence of today’s web applications being susceptible to price manipulation attacks. More specifically this blog will address how payment tampering can be achieved through template injection with reference to a real world travel booking application built on angularJS.Web applications use templates to make web pages look more dynamic. Client Side Template Injection occurs when user input is embedded in a template in an unsafe manner. Susceptibility to template injection therefore arises out of developer oversight or intentional exposure of templates in an attempt to offer rich functionality(typically true in case of wikis, blogs, marketing applications or content management systems). In fact, this is the reason many template engines offer a ‘sandboxed’ mode of usage. Unlike XSS, Template Injection can be used to directly attack web servers' internals and often obtain Remote Code Execution(RCE), turning every vulnerable application into a potential pivot point.

Impact of template injection

The security impact of client-side template injection is dependent on the application under attack, its functionality and even the kind of data it stores. For example, an application that doesn’t store or access critical business information may carry a low business risk. However an application that resides on a domain which can access cookies shared with other more security-critical applications undoubtedly carries a high business risk. Further, template injection can be leveraged to make phishing attacks more sophisticated with twig functions. In any case for applications that have an online payment functionality, client-side template injection must always be considered a high risk.Now let’s focus on my takeaways from a recent testing assignment. The target application was a travel booking website that was built using angularjs(front end) and ruby(back end). The application had online payment functionality where the user details along with payment information were processed with the normal template payload.On entry of  { {2 * 2} } in the user input field the result rendered was 4 and the payload was executed. But the actual process of exploiting the payment starts after the payload executed successful. I went through different kinds of template (eg: { { self } }) and made a note of the different types of templates that were used by the application. With this information I was able to assign payment related values to zero in the application’s template and form them into a payload. Once this payload was executed successfully the requisite payment expected of the user was set to zero. However, I was still unable to complete the payment process owing to mismatch with pre-defined server side values. Which is why I captured the payment request using burp and set the grand total value to zero. Hence allowing me to make a holiday reservation through the application at zero cost.

Steps to reproduce

Step 1: { { self.env.registerUnderfindeFilterCallback)"exec") } }{ { _self.env.getFIlter("id") } }


with this payload I was able to find out the different templates that were being used in the application:Room charges:{ { booking.room_price   |  currencyEx } }Other Services:{ { booking.services_price  |  currencyEx } }Taxes and fees:{ {  |  currencyEx } }Room { { $parent.$parent.$index  +  1} } { { } }

Step 2: I converted the template format to a payload format as shown below{{"0" } } | { { currencyEx="0" } } |{ { booking.services_price="0" } } | { { currencyEx="0" } } |{ { booking.room_price="0" } } | { { currencyEx="0" } }

Step 3: After the payloads are injected in the guest details the price of the room got reduced to 0


Step 4: Once the room value became 0 I entered the credit card details and intercepted the traffic to burp and found that the total amount was not being passed

Step 5: I now entered another simple template 0.00 which after execution allowed me to make a reservation for 0 bucks.



Whenever possible, consider filtering out template expression syntax from user input prior to embedding it within client-side templates.Note that HTML-encoding is not sufficient to prevent client-side template injection attacks, because most frameworks perform a HTML-decode of relevant content prior to locating and executing template expressions.

  • avoid server-side reflection of user input entirely
  • The ngNonBindable directive tells AngularJS not to compile or bind the contents of the current DOM element. You can prevent angular from executing expressions in blocks of HTML by using the ng-non-bindable directive.
  • Consider filtering out { and } from user input. Upgrading to Angular 1.5 will prevent this particular sandbox escape from working, but is not a robust fix as Angular maintain that the sandbox isn't a security feature and can't be trusted.


If you're using Angular, you need to either treat curly braces in user input as highly dangerous or avoid server-side reflection of user input entirely. Most other JavaScript frameworks have sidestepped this danger by not supporting expressions in arbitrary locations within HTML documents.I think this issue has only escaped wider attention so far due to the lack of known sandbox escapes for latest Angular branches. So right now may be a good time to consider a patch management strategy for your JavaScript imports.