HIGH server side template injectionbearer tokens

Server Side Template Injection with Bearer Tokens

How Server Side Template Injection Manifests in Bearer Tokens

Server Side Template Injection (SSTI) in Bearer Token implementations occurs when user-controlled data is embedded into template contexts without proper sanitization. In Bearer Token-based authentication systems, this vulnerability often manifests through template engines that process user input as part of token generation or validation workflows.

A common pattern involves dynamic token generation where user-provided claims are directly interpolated into template strings. Consider this vulnerable implementation:

function generateBearerToken(userInput) {
  const template = `{
    "sub": "${userInput}",
    "exp": "${Date.now() + 3600}"
  }`;
  return Buffer.from(template).toString('base64');
}

An attacker can exploit this by injecting template expressions. If the system uses a template engine like Handlebars or EJS, the following input would execute arbitrary code:

{{require('child_process').execSync('id').toString()}}

The vulnerability becomes more severe when Bearer Token systems integrate with template engines for claims processing. Many implementations use template engines to dynamically construct token payloads based on user attributes:

const template = require('template-engine');
const payload = template.render(tokenTemplate, userAttributes);
const token = jwt.sign(payload, secretKey);

Attackers can exploit this by crafting user attributes that contain template expressions. For example, if a user's email field is used in token generation:

{
  "email": "{{require('fs').readFileSync('/etc/passwd')}}"
}

Another manifestation occurs in Bearer Token introspection endpoints that render user data in templates. When these endpoints display token information without proper escaping, attackers can inject template expressions that execute when the introspection page loads.

Property-based SSTI in Bearer Tokens happens when token claims are used as template variables. If a system uses claims like 'role' or 'permissions' in template rendering without validation:

const roleTemplate = getUserRoleTemplate(userClaims.role);
const rendered = templateEngine.render(roleTemplate, userClaims);

An attacker with control over the 'role' claim can inject template expressions that execute with the privileges of the template engine.

Bearer Tokens-Specific Detection

Detecting SSTI in Bearer Token systems requires both static analysis and runtime testing. Static analysis should focus on identifying template engine usage patterns where user input flows into template contexts.

Code review patterns to identify:

# Look for template engine imports and user input flow
grep -r "require(['"]template" . --include="*.js"
grep -r "require(['"]ejs" . --include="*.js"
grep -r "require(['"]handlebars" . --include="*.js"

Dynamic detection involves testing token generation endpoints with template injection payloads. A comprehensive test suite should include:

const testPayloads = [
  '{{require("child_process").execSync("id").toString()}}',
  '{{require("fs").readFileSync("/etc/passwd")}}',
  '{{require("process").env}}',
  '{{this.constructor.constructor("return process")().mainModule.require("fs").readFileSync("/etc/passwd")}}'
];

For automated detection, middleBrick's black-box scanning approach tests Bearer Token endpoints without requiring source code access. The scanner sends template injection payloads in Authorization headers and analyzes responses for signs of template engine execution.

middleBrick specifically tests for:

  • Template expression evaluation in token claims
  • Property access through template syntax
  • Code execution through require() calls
  • Prototype pollution via template injection
  • Information disclosure through file system access

The scanner's LLM/AI Security module includes specialized checks for template injection patterns that might be missed by traditional scanners. It uses regex patterns to detect template syntax in responses and active probing to confirm execution.

Runtime monitoring should watch for unusual template engine errors or unexpected output patterns in token-related endpoints. Logging template engine exceptions can help identify attempted exploits.

Bearer Tokens-Specific Remediation

Remediating SSTI in Bearer Token systems requires a defense-in-depth approach. The primary mitigation is strict separation between user input and template contexts.

Safe token generation pattern:

function generateSecureBearerToken(userData) {
  // Validate and sanitize all user inputs
  const sanitized = {
    sub: sanitizeInput(userData.username),
    exp: Date.now() + 3600000,
    role: validateRole(userData.role)
  };
  
  // Never use user input directly in templates
  return jwt.sign(sanitized, process.env.JWT_SECRET, { expiresIn: '1h' });
}

function sanitizeInput(input) {
  return input.replace(/[^a-zA-Z0-9._-]/g, '');
}

function validateRole(role) {
  const validRoles = ['user', 'admin', 'moderator'];
  return validRoles.includes(role) ? role : 'user';
}

For systems that must use template engines, implement a whitelist approach:

const safeTemplate = require('safe-template-engine');

function renderSecureTemplate(template, data) {
  // Only allow specific properties
  const allowedProperties = ['username', 'email', 'role'];
  const safeData = {};
  
  allowedProperties.forEach(prop => {
    if (data[prop] !== undefined) {
      safeData[prop] = sanitizeInput(data[prop]);
    }
  });
  
  return safeTemplate.render(template, safeData);
}

Input validation should be context-aware. For Bearer Tokens, validate claims against expected formats:

function validateBearerClaims(claims) {
  const schema = {
    sub: /^[a-zA-Z0-9._-]+$/,
    exp: /^∞|[0-9]{10}$/,
    iat: /^∞|[0-9]{10}$/,
    role: /^(user|admin|moderator)$/
  };
  
  return Object.keys(schema).every(key => {
    if (claims[key] === undefined) return false;
    return schema[key].test(claims[key]);
  });
}

Content Security Policy headers can provide additional protection for web-based Bearer Token interfaces:

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123';

Implement runtime monitoring to detect template injection attempts:

function monitorTemplateEngine() {
  const originalRender = templateEngine.render;
  
  templateEngine.render = function(template, data) {
    if (containsTemplateInjection(data)) {
      console.warn('Template injection attempt detected:', data);
      throw new Error('Potential template injection detected');
    }
    return originalRender.call(this, template, data);
  };
}

For legacy systems where refactoring isn't immediately possible, implement template sandboxing:

const vm = require('vm');

function sandboxedRender(template, data) {
  const sandbox = {
    require: () => { throw new Error('require() blocked'); },
    process: { env: {} }
  };
  
  const context = vm.createContext(sandbox);
  return vm.runInContext(`"${template}"`, context);
}

Frequently Asked Questions

How can I test if my Bearer Token system is vulnerable to SSTI?

Send template injection payloads in token claims or Authorization headers and observe responses. Look for error messages containing template syntax, unexpected output, or server errors. middleBrick's black-box scanning can automate this testing by sending various injection payloads and analyzing responses for signs of template engine execution.

What's the difference between SSTI and XSS in Bearer Token contexts?

SSTI occurs when template engines process user input as code, executing server-side. XSS involves injecting client-side scripts that execute in users' browsers. In Bearer Token systems, SSTI is often more dangerous because it can lead to server compromise, data exfiltration, and complete system access, while XSS is typically limited to client-side impact.