Client-Side Template Injection (CSTI)
Client-Side Template Injection (CSTI) shows up when an application embeds user input inside a template that the browser evaluates, not the server. Frameworks like AngularJS, Vue or Mavo interpret {{ ... }} expressions in the DOM; if the text we control reaches an area the engine evaluates without escaping, that expression runs in the page context. Unlike SSTI (which runs on the server), CSTI executes on the client, so its natural payoff is XSS: session-cookie theft, actions on behalf of the victim, or a pivot into the rest of the application.
The probe is the same as in SSTI, but interpreted by the client framework: if injecting an arithmetic operation makes the page render the result instead of the literal text, the engine is evaluating.
{{7*7}} <!-- if the page prints 49, it evaluates the template -->
${7*7} <!-- variants depending on the engine -->Once evaluation is confirmed, you escape the framework sandbox to reach JavaScript. In modern AngularJS (>= 1.6, sandbox removed) simply reaching the Function constructor is enough:
{{constructor.constructor('alert(1)')()}}In older versions (1.5.x) the sandbox forces a more elaborate escape, published in PayloadsAllTheThings for each specific version. If the site also filters certain characters in the message (an alert('PWNED') that never fires), you dodge the filter by building the string with String.fromCharCode, which contains no quotes or suspicious letters:
{{constructor.constructor('alert(String.fromCharCode(80,87,78,69,68))')()}}Requirements. The input must be reflected inside a region the client template engine processes (not a plain <script> nor as escaped text) and the page must load a vulnerable framework. Identifying the framework and its version (via Ctrl+U on the source, or by the DOM's ng-*/v-* classes) is the step that decides which sandbox-escape payload to use.
How to detect it. There is barely a trace server-side: evaluation happens in the browser. The signature lives in inbound traffic, where a WAF flags {{...}}, constructor.constructor or String.fromCharCode in parameters that end up rendered. On the client, a strict CSP (script-src without unsafe-eval) breaks most of these escapes and its block is logged as a CSP violation, a reliable indicator of an attempt.
Defence. Never mix user data with client templates: treat input as text through the framework's safe binding (interpolation that escapes, never v-html nor compiling dynamic templates), keep the framework up to date (old sandboxes are insecure by design), and apply a CSP without unsafe-eval. Since CSTI ends in JavaScript execution, the defence overlaps with that of XSS.