Prove server-side template evaluation and identify its engine
Needs: The application evaluates attacker-controlled template syntax and the selected engine exposes a useful object or function
These are separate probes, not one universal payload
# These are separate probes, not one universal payload
# Jinja/Twig-style expression probe
curl -sS -G --data-urlencode 'name={{7*7}}' http://TARGET:PORT/PATH
# A different delimiter family, only when the first is literal or errors suggest it
curl -sS -G --data-urlencode 'name=${7*7}' http://TARGET:PORT/PATH
# Jinja-versus-Twig clue; interpret alongside source/errors, not in isolation
curl -sS -G --data-urlencode "name={{7*'7'}}" http://TARGET:PORT/PATH
Read: changed, repeatable computed output compared with a literal control supports evaluation.
49alone does not identify the engine. Jinja commonly repeats the string; Twig commonly treats it numerically. Confirm the engine/version and exposed objects before selecting a file-read or command primitive. Literal reflection → inspect another template/input boundary; a syntax error alone does not prove an exploitable expression.
Verify → Require repeatable computed output and corroborating engine clues; the value 49 alone does not identify the engine.
If it fails → Literal output rejects that syntax in the tested sink; a syntax error can be a parser clue but is not exploitation proof. More detail ↓
Explanation & examples
Prove server-side template evaluation and identify its engine
- USE WHEN
- Controlled input appears in a server-rendered template, preview, email or report
- STARTING ACCESS
- A reproducible application request and a controlled input or access-context comparison
- RESULT
- A verified template-evaluation primitive and an engine/version-specific next test
Recognize the clue
Inspect mapped previews, reports and server-rendered inputs for template syntax clues; preserve the normal request and literal control.
curl -sS -G --data-urlencode 'name={{7*7}}' http://TARGET:PORT/PATH
Literal control: 7*7
Expression response: 49Means: A repeatable computed result supports evaluation in that syntax but does not identify the engine or command capability.
Confirm: Correlate error/source/framework clues and test a discriminating engine expression before selecting objects.
- After validation
- One engine family and its exposed primitive are confirmed: choose the matching bounded method.
- Ruled out in this context
- All candidate syntax remains literal in the actual rendered sink: reject SSTI there.
- Still inconclusive
- A syntax error alone leaves parser identity and exploitability unresolved.
Troubleshooting: Literal output rejects that syntax in the tested sink; a syntax error can be a parser clue but is not exploitation proof.
Use when controlled text appears inside a server-rendered template, email preview or report. Replay the real parameter and session. These are separate probes, not one universal payload:
Read: changed, repeatable computed output compared with a literal control supports evaluation. 49 alone does not identify the engine. Jinja commonly repeats the string; Twig commonly treats it numerically. Confirm the engine/version and exposed objects before selecting a file-read or command primitive. Literal reflection → inspect another template/input boundary; a syntax error alone does not prove an exploitable expression.
Sources: upstream 1.
Why it works
A computed expression proves evaluation only in that syntax. File or command effects depend on the actual engine, sandbox and exposed objects.
Worked example · hypothetical
Observation: a preview renders controlled input. Test: compare a literal control and two delimiter families. Illustrative output: one expression computes while the others remain literal. Interpretation: narrow the engine before choosing a primitive.
New identity, privilege, host or route? Re-enumerate → All topic tasks →