HIGH server side template injectionsailshmac signatures

Server Side Template Injection in Sails with Hmac Signatures

Server Side Template Injection in Sails with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Server Side Template Injection (SSTI) in Sails becomes particularly risky when Hmac Signatures are used to validate or bind data to templates. SSTI occurs when an attacker can control part of a template expression and cause the server to evaluate unintended logic. In Sails, views often render dynamic data using template engines such as EJS or Lodash, and developers sometimes use Hmac Signatures to ensure data integrity—for example, signing configuration values or template parameters to confirm they have not been tampered with.

If user-influenced input is incorporated into the logic that determines which template is rendered or how signature verification is performed, an attacker may be able to inject template code that changes the execution path. For instance, suppose a Sails application uses a signature to verify a selected layout or a feature flag stored in a template context. An attacker could provide a malicious payload that modifies the resolved template or causes the application to evaluate expressions that execute unintended server-side logic. This can lead to information disclosure, unauthorized actions, or exposure of internal data structures, especially when the signature verification does not strictly validate the origin and scope of the data being signed.

The combination of SSTI and Hmac Signatures can expose subtle trust boundary issues. A developer might assume that because a value is signed, it is safe to interpolate into a template. However, if the signature is verified after the template context is already built—rather than before the template is selected or rendered—an attacker can still manipulate template selection or variable evaluation. For example, an attacker could inject a value that changes which partial is rendered, or which helper functions are invoked, bypassing intended access controls. In Sails, this often manifests in controllers that pass user input into view locals and then apply signature checks on only a subset of those values, leaving the rest open to template-level manipulation.

Real-world attack patterns mirror standard OWASP API Top 10 API05:2023 Server Side Template Injection, where untrusted data is rendered in templates. In the context of Hmac Signatures, CVE-like scenarios arise when signature verification is incomplete or applied inconsistently. For instance, if a signature is computed over a JSON object but the template engine still processes additional user-supplied fields, the integrity protection does not prevent injection. This can allow an attacker to execute arbitrary template code, access restricted properties, or influence which backend logic runs, all while the application believes the data is authentic due to the signature.

To understand the risk, consider a Sails controller that signs a layout parameter and passes it to the view. If the layout name is not strictly validated and is instead directly interpolated into the template engine’s include or render function, an attacker could provide a payload such as {{this}} or function calls that execute server-side logic. Even with a valid Hmac Signature on other parameters, the unchecked layout input can change which template partials are rendered, leading to unintended data exposure or code execution. The key takeaway is that Hmac Signatures protect data integrity but do not automatically prevent template injection if input validation and context-aware rendering controls are not enforced independently.

Hmac Signatures-Specific Remediation in Sails — concrete code fixes

Remediation focuses on strict input validation, safe template rendering, and consistent application of Hmac Signatures before any data reaches the template engine. In Sails, ensure that any data used to select templates, include partials, or invoke helpers is validated against an allowlist and never directly interpolated from user input. Hmac Signatures should be computed over a canonical representation of the data and verified before the data is used in any rendering decision. This prevents attackers from altering the logic that determines which template or helper is executed.

Use strict schema validation for all user inputs that influence template rendering. For example, if a layout or partial name is required, define a fixed set of allowed values and verify the input against that set before passing it to the view. Do not rely on signature checks alone to sanitize inputs that affect control flow. Below is a concrete Sails controller example that safely uses Hmac Signatures and avoids SSTI by validating inputs before rendering.

const crypto = require('crypto');

module.exports = {
  renderDashboard: async function (req, res) {
    const { layout, widgetData, signature } = req.allParams();

    const allowedLayouts = ['default', 'compact', 'detailed'];
    if (!allowedLayouts.includes(layout)) {
      return res.badRequest('Invalid layout');
    }

    const computedSignature = crypto
      .createHmac('sha256', process.env.HMAC_SECRET)
      .update(JSON.stringify({ layout, widgetData }))
      .digest('hex');

    if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computedSignature))) {
      return res.unauthorized('Invalid signature');
    }

    return res.view('dashboard', {
      layout: layout,
      data: widgetData,
    });
  },
};

This approach ensures that layout is restricted to known-safe values before it is used in rendering, independent of the signature verification. The Hmac Signature is computed over both the layout and the data, ensuring that any tampering with either value will cause verification to fail. Using crypto.timingSafeEqual prevents timing attacks on signature comparison, which is critical for secure Hmac verification.

Additionally, avoid passing raw user input directly to template helpers or includes. Instead, map validated inputs to predefined template partials and use strict context handling. If your Sails app uses Lodash templates or EJS, ensure that the template engine’s evaluation scope is limited and that dangerous functions or properties are not exposed. The following example demonstrates how to safely pass signed data to an EJS template without enabling arbitrary code execution.

const crypto = require('crypto');

module.exports = {
  profile: async function (req, res) {
    const { tab, signature } = req.allParams();

    const validTabs = ['overview', 'settings', 'activity'];
    if (!validTabs.includes(tab)) {
      return res.badRequest('Invalid tab');
    }

    const payload = { tab, userId: req.session.userId };
    const computedSignature = crypto
      .createHmac('sha256', process.env.HMAC_SECRET)
      .update(JSON.stringify(payload))
      .digest('hex');

    if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computedSignature))) {
      return res.unauthorized('Invalid signature');
    }

    const templateData = {
      tab: payload.tab,
      userProfile: await User.findOne(req.session.userId),
    };

    return res.view('profile', templateData);
  },
};

In this pattern, the signed payload controls only which validated tab is rendered, while all other data is fetched from trusted sources. The template itself receives no user-controlled expressions that could lead to SSTI. By combining allowlist validation, Hmac Signatures over the relevant parameters, and strict separation of data from control flow, Sails applications can defend against Server Side Template Injection while maintaining integrity checks on critical parameters.

Frequently Asked Questions

Can Hmac Signatures alone prevent Server Side Template Injection in Sails?
No. Hmac Signatures protect data integrity but do not prevent template injection if inputs that affect template selection or rendering are not validated separately. Always validate and allowlist inputs before using them in templates.
What should I do if my Sails app uses dynamic template names based on user input?
Map user input to a predefined allowlist of template names, verify the input against that list, and compute Hmac Signatures over the combined data before rendering. Do not directly interpolate user input into template names or paths.