SSTI (Server-Side Template Injection) acontece quando o input do usuário é processado diretamente dentro de uma engine de template no servidor.
Isso pode permitir desde simples vazamentos até execução remota de código (RCE).
Após confirmar uma possível SSTI, o próximo desafio é descobrir qual engine de template está processando a entrada — informação essencial para validação, mitigação e reporte. Este guia compartilha a metodologia testada que usamos para descobrir a tecnologia por trás dos templates de forma rápida e confiável.
{{ }}
com blocos/sections usando {{#if ...}}{{/if}}
, {{#each ...}}{{/each}}
, {{#unless ...}}
{{! comment }}
ou {{!-- comment --}}
{{{var}}}
handlebars
, express-handlebars
, handlebars.runtime
, ou Missing helper
Missing helper: "nomeDoHelper"
payloads:
{{!comment_handlebars}}
{{!-- long comment --}}
O que observar:
{{!comment_handlebars}}
aparece literal → provavelmente não é Handlebars.#if
, #each
)payloads:
{{#if true}}YES{{/if}}
O que observar:
YES
→ engine avalia o bloco (Handlbars aceita #if/#each).payloads:
{{7*7}}
{{{7*7}}}
O que observar:
7*7
literal.49
→ é Jinja/Twig/Nunjucks/Freemarker etc. (não Handlebars).payloads:
{{{"<b>OK</b>"}}}
O que observar:
<b>OK</b>
renderizado sem entidades (tag ativa) → engine suporta {{{ }}}
(Handlbars e Mustache suportam triple mustache).<b>OK</b>
→ escape automático está ativo.payloads:
{{#each [1,2]}}X{{/each}}
{{> partialName}}
O que observar:
each
e >
(partials) são sintaxes Handlebars; se você vê X
repetido ou partials sendo incluídos, é um indicativo.{{unknownHelper}}
e resposta contém Missing helper
→ forte sinal de Handlebars.{{7*7}}
→ se 49
, descarta Handlebars.{{!hb}}
e {{!--hb--}}
→ se removido, ponto para Handlebars.{{#if true}}OK{{/if}}
→ se OK
, ponto para Handlebars.{{{ "<b>OK</b>" }}}
→ se HTML ativo, triple-stash suportado.Missing helper
/ handlebars
no trace.<% %>
, <%= %>
, <%- %>
nas respostas ou em fontes/paths.ejs
expostos em comentários, erros ou caminhos (views/*.ejs)
ejs
ou EJS
(ou express
+ referência a arquivos .ejs
)X-Powered-By: Express
junto com templates que usam <%
é um bom indíciopayloads:
<%= 7*7 %>
O que observar:
"49"
→ engine avalia JS dentro de <%= %>
(forte indício de EJS ou similar).<%= 7*7 %>
) → delimitadores não estão sendo processados.payloads:
<%= "<b>OK</b>" %>
<%- "<b>OK</b>" %>
O que observar:
<b>OK</b>
) se for <%=
.<b>OK</b>
) se for <%-
.payloads:
<% var x = 1; %>HELLO
O que observar:
HELLO
aparece sem o scriptlet, ok.<% /* comentário */ %>
— injetar isto normalmente não aparece na saída.payloads:
<%= nonexistentVar %>
O que observar:
ReferenceError: nonexistentVar is not defined
ou stack trace Node, pode revelar Node/EJS.<%= 7*7 %>
→ se 49
, provavelmente engine que avalia JS (EJS / ERB-like; combine com outros testes).<%- "<b>OK</b>" %>
→ se HTML renderizado, ponto forte para EJS (raw output).<% /* comment */ %>
→ se o comentário some (delimitadores <%
processados).<%= nonexistentVar %>
e verifique por ReferenceError
/stack trace Node..ejs
em paths, por X-Powered-By: Express
e por menções a ejs
/express
em erros.{{ ... }}
, {% ... %}
, {# ... #}
..njk
, .nunjucks
ou referências a views/*.njk
expostos em comentários, erros ou caminhos.nunjucks
, nunjucks.configure()
ou nunjucks.render
.X-Powered-By: Express
combinado com templates que usam {% %}
/{{ }}
e presença do pacote nunjucks
no código/erro.payloads:
{{ 7*7 }}
O que observar:
49
→ engine avalia expressões (forte indício de Nunjucks / Jinja-like).{{ 7*7 }}
) → delimitadores não estão sendo processados.payloads:
{% if true %}YES{% endif %}
{% for i in [1,2] %}X{% endfor %}
O que observar:
YES
→ {% if %}
foi interpretado.XX
→ for
/endfor
processados (sintaxe Jinja-like).payloads:
{# teste comentario #}
O que observar:
{# #}
suportada (indício de engines Jinja-like, incluindo Nunjucks).payloads:
{{ "abc" | upper }}
{{ [1,2] | length }}
O que observar:
ABC
→ filtro upper
aplicado.2
→ filtro length
processado (outro forte indício de Nunjucks).payloads:
{{ unknownVar }}
O que observar:
unknownVar is not defined
ou stack trace nunjucks
, confirma o uso.{{ 7*7 }}
→ se 49
, engine JS/Jinja-like (forte indício de Nunjucks).{% if true %}YES{% endif %}
→ se YES
, confirma blocos ativos.{{ "abc" | upper }}
→ se ABC
, confirma filtros Nunjucks.{# comentario #}
some.nunjucks
, Template render error
, nunjucks.configure
, etc.{% %}
, {{ }}
ou <% %>
.pug
, jade
, pug.compile()
, pug.render()
..pug
ou .jade
em caminhos, mensagens de erro ou diretórios (views/*.pug
).X-Powered-By: Express
com estruturas HTML altamente minificadas ou indentadas de forma incomum (padrão de saída do Pug).payloads:
#{7*7}
O que observar:
49
→ expressões JS avaliadas dentro de #{}
(forte indício de Pug).#{7*7}
) → não está sendo processado.payloads:
#{'<b>OK</b>'}
!{'<b>OK</b>'}
O que observar:
<b>OK</b>
), é escapado.<b>OK</b>
, confirma suporte à interpolação raw (!{}
).payloads:
if true
OK
O que observar:
OK
→ o bloco if
foi interpretado (forte indício de Pug).payloads:
each val in [1,2]
= val
O que observar:
12
→ each
foi processado, confirmando engine Pug/Jade.payloads:
#{unknownVar}
O que observar:
pug
ou jade
(Cannot read property ... in pug
), confirmação direta.#{7*7}
→ se 49
, indica Pug ou Jade.!{'<b>OK</b>'}
→ se renderiza HTML, Pug confirmado.if true\n OK
→ se OK
, engine processa lógica indentada..pug
ou .jade
em erros, paths ou stack traces.pug.compile
, template.pug
ou jade.runtime
são confirmação direta.{{ }}
sem suporte a lógica (sem {% %}
, <% %>
ou blocos if/for
).mustache
, hogan.js
, mustache.render()
ou Hogan.compile()
..mustache
ou .hjs
visíveis em caminhos (views/*.mustache
).{ {{{ }}} }
(não escapados) é um indicativo forte de Mustache/Hogan.payloads:
{{7*7}}
O que observar:
{{7*7}}
→ Mustache não avalia expressões (esperado).49
→ não é Mustache (provavelmente Nunjucks, Jinja, etc).payloads:
{{title}}
O que observar:
"Home"
ou "Page"
) → substituição de variável simples.{{title}}
, variável não está no contexto.payloads:
{{ "<b>OK</b>" }}
{{{ "<b>OK</b>" }}}
O que observar:
<b>OK</b>
).<b>OK</b>
).payloads:
{{#true}}YES{{/true}}
{{^false}}NO{{/false}}
O que observar:
YESNO
→ seções processadas.payloads:
{{! este é um comentário }}
O que observar:
{{! ... }}
suportada (indício claro de Mustache/Hogan).{{7*7}}
→ se não vira 49
, engine não executa código (característica de Mustache).{{{ "<b>OK</b>" }}}
→ se renderiza HTML, confirma suporte a triplo mustache.{{! comentario }}
→ se o comentário some, confirma Mustache-like..mustache
ou .hjs
em paths, erros ou stack traces.mustache.render
, Hogan.compile
, Cannot find section
, etc.{{ ... }}
, {% ... %}
, {# ... #}
(semelhante a Nunjucks).jinja2
, TemplateSyntaxError
, UndefinedError
, ou jinja2.environment
..jinja
, .jinja2
, .html
com menções a Jinja nos caminhos (templates/*.jinja2
).Server: Werkzeug
, X-Powered-By: Flask
, ou respostas típicas de frameworks Python.payloads:
{{ 7*7 }}
O que observar:
49
→ engine avalia expressões (forte indício de Jinja2).{{ 7*7 }}
) → delimitadores não processados.payloads:
{{ "abc"|upper }}
{{ [1,2,3]|length }}
O que observar:
ABC
→ filtro upper
processado.3
→ filtro length
aplicado (confirmação clara de Jinja2).payloads:
{% if true %}YES{% endif %}
{% for i in [1,2] %}X{% endfor %}
O que observar:
YES
→ {% if %}
interpretado.XX
→ laço for
processado corretamente.payloads:
{# comentario #}
O que observar:
{# #}
(forte evidência de Jinja2).payloads:
{{ unknown_var }}
O que observar:
jinja2.exceptions.UndefinedError
ou traceback Python → confirmação direta.{{ 7*7 }}
→ se 49
, engine Jinja-like.{{ "abc"|upper }}
→ se ABC
, confirma filtros Jinja2.{% if true %}YES{% endif %}
→ se YES
, confirma blocos ativos.{# comentario #}
desaparece.jinja2
, TemplateSyntaxError
, UndefinedError
.<% %>
, ${ }
, <%! %>
(mistura de estilo JSP e Python).mako
, mako.template
, mako.runtime
, ou mako.exceptions
..mako
em caminhos, mensagens de erro ou diretórios (templates/*.mako
).Server: Werkzeug
, Server: gunicorn
, ou aplicações Python (Flask/Pyramid) com saída de template.<% ... %>
ou ${ ... }
é sinal clássico de Mako.payloads:
${7*7}
O que observar:
49
→ expressões Python avaliadas (forte indício de Mako).${7*7}
→ delimitadores não processados.payloads:
<% x = 1 %>OK
O que observar:
OK
for exibido sem erro → bloco <% %>
aceito (característico de Mako).payloads:
<% if True: %>YES<% endif %>
O que observar:
YES
for exibido → confirma execução de blocos Python no servidor.payloads:
${"<b>OK</b>"}
O que observar:
<b>OK</b>
).<b>OK</b>
), engine pode estar configurada com default_filters=['h']
.payloads:
${unknown_var}
O que observar:
NameError: name 'unknown_var' is not defined
ou stack trace mako.exceptions
→ confirmação direta.${7*7}
→ se 49
, expressões Python ativas (forte indício de Mako).<% if True: %>YES<% endif %>
→ se YES
, blocos de controle processados.${"<b>OK</b>"}
renderiza HTML direto (sem escapar).mako.exceptions
, mako.template
, NameError
..mako
em caminhos, mensagens ou stack traces.{{ ... }}
e {% ... %}
, porém sem suporte a execução direta de código Python.django.template
, TemplateSyntaxError
, VariableDoesNotExist
, ou django.core
..html
em diretórios templates/
(padrão do Django).Server: WSGIServer
, X-Frame-Options: DENY
, ou páginas de erro com o estilo visual padrão do Django (<h1>TemplateSyntaxError</h1>
).|safe
, |length
, |upper
, {% url %}
, {% csrf_token %}
, etc.).payloads:
{{ 7*7 }}
O que observar:
{{ 7*7 }}
→ não executa código (esperado no Django).49
aparecer → não é Django (provável Jinja2, Nunjucks, etc.).payloads:
{{ request.path }}
{{ user.username }}
O que observar:
/index/
ou admin
) → variável de contexto resolvida.payloads:
{{ "abc"|upper }}
{{ [1,2,3]|length }}
O que observar:
ABC
e 3
→ filtros padrão de Django funcionando.Invalid filter
) → possivelmente engine customizada.payloads:
{% if True %}YES{% endif %}
O que observar:
Invalid block tag
) → Django não reconhece True
literal (espera variável de contexto).YES
aparecer → engine Jinja-like, não Django.payloads:
{% comment %}teste{% endcomment %}
O que observar:
{{ ... }}
, {% ... %}
, {# ... #}
(Jinja-like, mas em PHP)..twig
ou menções a templates/*.twig
em erros ou caminhos.Twig\Environment
, Twig\Error
, Twig\Loader
.X-Powered-By: PHP
, Server: nginx/apache
) combinados com templates Twig.|escape
, |length
, |upper
, |raw
, |join
) presentes nas respostas.payloads:
{{ 7*7 }}
O que observar:
49
→ expressões avaliadas (forte indício de Twig).{{ 7*7 }}
→ delimitadores não processados.payloads:
{{ "abc"|upper }}
{{ [1,2,3]|length }}
O que observar:
ABC
→ filtro upper
processado.3
→ filtro length
processado (confirmação Twig).payloads:
{% if true %}YES{% endif %}
O que observar:
YES
→ bloco {% %}
interpretado.payloads:
{% for i in [1,2] %}X{% endfor %}
O que observar:
XX
→ loop processado, confirma engine Twig.payloads:
{# comentário #}
O que observar:
{# #}
(indício claro de Twig).payloads:
{{ unknownVar }}
O que observar:
Twig\Error\RuntimeError
ou Variable "unknownVar" does not exist
→ confirmação direta.{{ 7*7 }}
→ se 49
, engine Twig ativa.{{ "abc"|upper }}
→ se ABC
, filtros Twig funcionando.{% if true %}YES{% endif %}
→ se YES
, blocos interpretados.{# comentário #}
→ se desaparece, confirma engine.Twig\Environment
, Twig\Error
, Variable "..." does not exist
..twig
em paths ou mensagens de erro.{...}
para variáveis e funções, {* ... *}
para comentários..tpl
visíveis em caminhos (templates/*.tpl
) ou mensagens de erro.Smarty_Internal_Template
, SmartyException
, Smarty->fetch()
.X-Powered-By: PHP
) combinados com templates com sintaxe {variable}
.{$var|escape}
, {$arr|count}
, {foreach $items as $i}
) presentes nas respostas.payloads:
{$testVar}
O que observar:
{$testVar}
→ delimitadores não processados.payloads:
{$htmlVar}
{$htmlVar nofilter}
O que observar:
<b>OK</b>
).<b>OK</b>
) → suporte a nofilter
.payloads:
{foreach $items as $item}
{$item}
{/foreach}
O que observar:
payloads:
{if $cond}YES{/if}
O que observar:
YES
aparece → bloco condicional processado.payloads:
{* comentário *}
O que observar:
{* *}
.payloads:
{$unknownVar}
O que observar:
Smarty
→ confirmação da engine.{$testVar}
→ se variável é resolvida, Smarty ativa.{$htmlVar nofilter}
→ se renderiza HTML, confirma suporte a raw output.{foreach $items as $item}...{/foreach}
→ se loop processa, engine confirmada.{* comentário *}
→ se desaparece, engine Smarty.Smarty_Internal_Template
, SmartyException
..tpl
em paths ou mensagens de erro.{{ ... }}
para variáveis e {!! ... !!}
para saída sem escape..blade.php
em diretórios resources/views/*.blade.php
.Illuminate\View\View
, BladeCompiler
, ou ViewException
.X-Powered-By: PHP
) combinados com templates Blade.@if
, @foreach
, @include
, @csrf
, @extends
, @section
, etc.payloads:
{{ 7*7 }}
O que observar:
49
→ expressão é avaliada (Blade processa PHP/expressões).{{ 7*7 }}
→ delimitadores não processados.payloads:
{{ "<b>OK</b>" }}
{!! "<b>OK</b>" !!}
O que observar:
<b>OK</b>
).<b>OK</b>
).payloads:
@if(true)
YES
@endif
O que observar:
YES
aparece → diretiva interpretada (confirma Blade).payloads:
@foreach([1,2] as $i)
{{ $i }}
@endforeach
O que observar:
12
aparece → loop processado.payloads:
{{-- comentário --}}
O que observar:
payloads:
{{ $unknownVar }}
O que observar:
BladeCompiler
, ViewException
→ confirmação da engine.{{ 7*7 }}
→ se 49
, Blade processando expressões.{!! "<b>OK</b>" !!}
→ HTML renderizado sem escape, confirma raw output.@if(true)...@endif
e @foreach
→ se processados, diretivas Blade ativas.{{-- comentário --}}
→ se desaparece, engine confirmada.BladeCompiler
, ViewException
, Illuminate\View\View
..blade.php
em paths ou mensagens de erro.${ ... }
para variáveis e <# ... >
ou <#-- ... -->
para diretivas e comentários..ftl
visíveis em caminhos (templates/*.ftl
) ou mensagens de erro.freemarker.template.Template
, freemarker.core
, TemplateException
.Server: Apache-Coyote/1.1
, Servlet
, Spring
) combinados com templates FreeMarker.<#if>
, <#list>
, <#include>
, <#macro>
, <#assign>
.payloads:
${7*7}
O que observar:
49
→ expressão avaliada (FreeMarker processando).${7*7}
→ delimitadores não processados.payloads:
<#if true>
YES
</#if>
O que observar:
YES
aparece → bloco <#if>
interpretado.payloads:
<#list [1,2] as i>
${i}
</#list>
O que observar:
12
aparece → loop processado (confirma FreeMarker).payloads:
<#-- comentário -->
O que observar:
payloads:
${"<b>OK</b>"?html}
O que observar:
<b>OK</b>
→ demonstra filtro ?html
.${"<b>OK</b>"?no_esc}
(ou equivalente) → saída sem escape.payloads:
${unknownVar}
O que observar:
freemarker.core.InvalidReferenceException
→ confirmação direta.${7*7}
→ se 49
, engine FreeMarker processando expressões.<#if true>YES</#if>
→ se YES
, diretivas FreeMarker interpretadas.<#list [1,2] as i>${i}</#list>
→ se 12
, loops processados.<#-- ... -->
→ se desaparecem, engine confirmada.freemarker.template
, freemarker.core
, InvalidReferenceException
..ftl
em paths ou mensagens de erro.$variable
para variáveis e #directive(...)
para diretivas (#if
, #foreach
, #set
, #include
)..vm
visíveis em caminhos (templates/*.vm
) ou mensagens de erro.org.apache.velocity.Template
, VelocityEngine
, VelocityException
.Server: Apache-Coyote/1.1
, Servlet
) combinados com templates Velocity.#if
, #foreach
, #set
, #include
, #macro
.payloads:
$testVar
O que observar:
$testVar
→ delimitadores não processados.payloads:
#if($true)
YES
#end
O que observar:
YES
aparece → diretiva condicional interpretada.payloads:
#foreach($i in [1,2])
$i
#end
O que observar:
12
aparece → loop processado (confirma Velocity).payloads:
## comentário
O que observar:
##
ou #* ... *#
.payloads:
$unknownVar
O que observar:
VelocityException
ou referência a unknownVar
→ confirmação direta.$testVar
→ se variável é resolvida, Velocity ativa.#if($true)YES#end
→ se YES
, diretiva interpretada.#foreach($i in [1,2])$i#end
→ se 12
, loops processados.## comentário
→ se desaparecem, engine confirmada.VelocityEngine
, VelocityException
, org.apache.velocity.Template
..vm
em paths ou mensagens de erro.th:text
, th:utext
, th:if
, th:each
, th:include
, th:replace
..html
em diretórios templates/
com namespace de atributos th:
.org.thymeleaf.TemplateEngine
, TemplateProcessingException
.Server: Apache-Coyote/1.1
, Servlet
) combinados com templates Thymeleaf.${...}
dentro de atributos th:
para interpolação de variáveis.payloads:
<p th:text="${7*7}">Fallback</p>
O que observar:
49
→ expressão avaliada (Thymeleaf processando).Fallback
→ delimitadores não processados.payloads:
<p th:text="'<b>OK</b>'">Fallback</p>
<p th:utext="'<b>OK</b>'">Fallback</p>
O que observar:
th:text
→ saída escapada (<b>OK</b>
).th:utext
→ saída renderizada como HTML (<b>OK</b>
).payloads:
<p th:if="${true}">YES</p>
O que observar:
YES
aparece → diretiva th:if
interpretada.YES
não aparece → não processado.payloads:
<ul>
<li th:each="i : ${[1,2]}">${i}</li>
</ul>
O que observar:
1 2
→ loop processado (Thymeleaf ativo).payloads:
<p th:text="${unknownVar}">Fallback</p>
O que observar:
TemplateProcessingException
→ confirmação direta.<p th:text="${7*7}">Fallback</p>
→ se 49
, engine Thymeleaf processando expressões.<p th:utext="'<b>OK</b>'">Fallback</p>
→ saída HTML, raw output.<p th:if="${true}">YES</p>
→ se YES
, diretiva interpretada.<li th:each="i : ${[1,2]}">${i}</li>
→ se 1 2
, iteração processada.TemplateProcessingException
, org.thymeleaf.TemplateEngine
..html
com atributos th:
em paths ou mensagens de erro.<% ... %>
para execução de código e <%= ... %>
para output..erb
ou .html.erb
em diretórios app/views/*.erb
ou app/views/**/*.html.erb
.ERB::Compiler
, ERB#result
, ActionView::Template::Error
.Server: Puma
, Server: WEBrick
) combinados com templates ERB.<%# ... %>
para comentários, que não aparecem na saída renderizada.payloads:
<%= 7*7 %>
O que observar:
49
→ ERB processando expressão Ruby.<%= 7*7 %>
→ delimitadores não processados.payloads:
<% x = 1 %>HELLO
O que observar:
HELLO
deve aparecer normalmente.payloads:
<%= "<b>OK</b>" %>
O que observar:
<b>OK</b>
como HTML, ERB não escapa por padrão.payloads:
<%# este é um comentário %>
O que observar:
payloads:
<%= unknown_var %>
O que observar:
NameError
ou stack trace ERB
aparece → confirmação da engine.<%= 7*7 %>
→ se 49
, ERB processando expressão.<% x = 1 %>HELLO
→ se HELLO
aparece, scriptlets aceitos.<%= "<b>OK</b>" %>
→ HTML renderizado sem escape.<%# comentário %>
→ se sumir, confirma ERB.ERB::Compiler
, ERB#result
, NameError
..erb
ou .html.erb
em paths ou mensagens de erro.{{ ... }}
para variáveis e {% ... %}
para tags..liquid
ou .html
com tags Liquid em diretórios de templates (templates/*.liquid
).Liquid::Template
, Liquid::Error
, Liquid::ParseError
.| upcase
, | size
, | strip
, | escape
) e tags (for
, if
, include
, assign
).{% comment %} ... {% endcomment %}
ou {# ... #}
.payloads:
{{ 7*7 }}
O que observar:
{{ 7*7 }}
.49
aparece → não é Liquid (provável ERB/Jinja).payloads:
{{ page.title }}
O que observar:
payloads:
{{ "abc" | upcase }}
{{ [1,2,3] | size }}
O que observar:
ABC
→ filtro aplicado.3
→ filtro aplicado (indício de Liquid).payloads:
{% if true %}YES{% endif %}
O que observar:
YES
aparece → bloco processado.payloads:
{% for i in (1..2) %}{{ i }}{% endfor %}
O que observar:
12
aparece → loop processado (confirma Liquid).payloads:
{% comment %} comentário {% endcomment %}
O que observar:
{{ 7*7 }}
→ se literal, Liquid ativo (não executa código).{{ "abc" | upcase }}
→ se ABC
, confirma suporte a filtros.{% if true %}YES{% endif %}
→ se processado, blocos condicional ativos.{% for i in (1..2) %}{{ i }}{% endfor %}
→ se 12
, iteração processada.{% comment %} ... {% endcomment %}
→ se sumir, engine confirmada.Liquid::Template
, Liquid::Error
, Liquid::ParseError
.{{ ... }}
para variáveis, funções e blocos de controle..tmpl
, .gohtml
, .html
ou diretórios templates/
usados em projetos Go.text/template.Template
, html/template.Template
, Execute
, ExecuteTemplate
.len
, index
, printf
, html
, urlquery
).{{ if ... }}
, {{ range ... }}
, {{ with ... }}
, {{ end }}
.payloads:
{{ 7*7 }}
O que observar:
{{ 7*7 }}
.49
aparece → engine diferente (Jinja, ERB, etc.).payloads:
{{ .Title }}
O que observar:
payloads:
{{ if true }}YES{{ end }}
O que observar:
YES
aparece → bloco processado (Go Template ativo).payloads:
{{ range $i, $v := .Items }}{{ $v }}{{ end }}
O que observar:
payloads:
{{/* comentário */}}
O que observar:
payloads:
{{ .UnknownVar }}
O que observar:
template: ...: can't evaluate field UnknownVar
→ confirmação direta.{{ 7*7 }}
→ se literal, Go Template ativo (não executa aritmética).{{ .Title }}
→ se valor do contexto aparece, substituição de variável funcionando.{{ if true }}YES{{ end }}
→ se YES
, diretivas processadas.{{ range $i, $v := .Items }}{{ $v }}{{ end }}
→ se processado, range ativo.{{/* comentário */}}
→ se sumir, engine confirmada.text/template.Template
ou html/template.Template
.@
para variáveis, expressões e blocos de código (@{ ... }
)..cshtml
ou .vbhtml
em diretórios Views/
de projetos ASP.NET ou ASP.NET Core.Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine
, RazorPage
, ou RazorCompilation
.Server: Kestrel
, Server: IIS
) combinados com templates Razor.@if
, @for
, @foreach
, @section
, @Html.Partial
, @RenderBody
, @model
.payloads:
@DateTime.Now.Year
O que observar:
@DateTime.Now.Year
→ delimitadores não processados.payloads:
@{
var x = 1;
}
HELLO
O que observar:
HELLO
deve aparecer normalmente.payloads:
@if(true){
<text>YES</text>
}
O que observar:
YES
aparece → diretiva interpretada (confirma Razor).payloads:
@for(int i = 1; i <= 2; i++){
@i
}
O que observar:
12
aparece → loop processado corretamente.payloads:
@* comentário *@
O que observar:
payloads:
@unknownVar
O que observar:
RazorPage
ou RazorCompilation
→ confirmação direta.@DateTime.Now.Year
→ se valor aparece, Razor processando expressões C#.@{ var x=1; }HELLO
→ se HELLO
, scriptlets aceitos.@if(true){<text>YES</text>}
→ se processado, diretiva interpretada.@for(int i=1;i<=2;i++){@i}
→ se 12
, iteração ativa.@* comentário *@
→ se sumir, engine confirmada.RazorPage
, RazorCompilation
, Microsoft.AspNetCore.Mvc.Razor
.