The Ravens’ portal greets you by name, but it builds the template text by pasting your name inside it, then renders it with a template engine. So what you type is evaluated as a template expression, and the template context has a config object holding the app secret.
The Ravens greeting portal builds a template from your name and renders it. Your name is pasted into the template text, so what you type becomes part of the template, not just data. The template context holds a config object with a secret.
Read the app secret config.secret by injecting a template expression.
You injected a template expression and read the app secret.
Why the solution worked
This is server-side template injection: your input entered the template text and became an expression the engine evaluates, not text it shows, so it reaches context variables and sometimes code execution. The fix: do not build the template from user input; pass the input as data (a variable) into a fixed template, so it is never evaluated, and use an engine that auto-escapes output.
The root cause
User input is pasted into the template text before rendering, becoming an expression the template engine evaluates. The root is mixing user data with template code.
How the code is fixed
User input is data passed to the template, not part of the template text. That rule kills SSTI.
Vulnerable code
app.post('/greet', (req, res) => {
// User input is the template: {{...}} gets evaluated.
res.send(engine.render('Hello ' + req.body.name, { config }));
});
Safe code
app.post('/greet', (req, res) => {
// Fixed template; the name is passed as DATA and only ever substituted, never evaluated.
res.send(engine.render('Hello {{ name }}', { name: req.body.name }));
});
Impact in the real world
Server-side template injection often leads to reading sensitive data and then to full code execution on the server in real template engines.
How defenders detect it
Defenders watch for template syntax in inputs and pass user data as template variables, never inside the template text.