HIGH server side template injectionsailsmongodb

Server Side Template Injection in Sails with Mongodb

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

Server Side Template Injection (SSTI) occurs when an attacker can inject template code that is subsequently evaluated by a server-side templating engine. In Sails.js, which encourages rapid development with minimal configuration, SSTI can manifest when user-controlled data is passed into template rendering functions or into view helpers that evaluate expressions. When the application also uses MongoDB as the primary data store, the risk profile changes because attacker-supplied input can flow directly into MongoDB queries constructed inside compromised templates.

Sails does not enforce a strict separation between data and code in all view paths. If a controller action passes request parameters into res.view() context without strict validation or escaping, and the view uses dynamic template logic (e.g., Lodash templates or custom helpers that evaluate JavaScript), an attacker may inject template directives that execute code. Because Sails often builds MongoDB queries from the same context passed to views, injected template code can manipulate query construction, leading to unintended query execution or data leakage.

For example, consider a Sails controller that renders a user profile page and passes the user-supplied username into the view context. If the view uses Lodash templating (the default in many Sails installations) and embeds the username inside a MongoDB query built via User.find(), an attacker could provide input like '}, { $where: "return false && exfiltrateData()"} to alter the query structure. While Sails/Waterline typically sanitizes inputs at the ORM layer, direct usage of eval-like helpers or unsafe interpolation in custom services can bypass these protections. The MongoDB driver then executes the attacker-influenced query, potentially returning sensitive documents or enabling further injection via MongoDB operators.

The combination of Sails’ flexible view system and MongoDB’s expressive query language amplifies the impact. Attackers can leverage SSTI to probe internal services, attempt Server Side Request Forgery (SSRF) against the MongoDB instance, or chain template execution with MongoDB aggregation pipelines if the application dynamically builds pipelines using injected template fragments. Because the attack surface includes both the template engine and the database layer, detection requires correlating runtime behavior across both components, which middleBrick’s 12 security checks perform in parallel, including Input Validation and SSRF testing.

Without runtime analysis, it is difficult to know whether a Sails application safely handles user input in templates and database interactions. middleBrick scans the unauthenticated attack surface of your endpoint in 5–15 seconds, testing for SSTI vectors and MongoDB-specific anomalies such as unexpected query patterns. Its findings map to OWASP API Top 10 and provide prioritized remediation guidance, helping you understand how template logic and database queries interact in your specific implementation.

Mongodb-Specific Remediation in Sails — concrete code fixes

Remediation focuses on strict input validation, avoiding dynamic evaluation in templates, and ensuring MongoDB queries are constructed with trusted data only. Do not rely on implicit escaping provided by Waterline alone when templates are involved.

1. Avoid dynamic template evaluation

Do not use Lodash templates (or any eval-like mechanism) to construct MongoDB queries or to render user-controlled content that influences queries. Replace dynamic templates with static views or use a dedicated serialization layer.

// ❌ Unsafe: dynamic Lodash template that builds a query string
const queryTemplate = _.template(req.query.filter); // user-controlled
const query = queryTemplate({ collection: 'users' });
const results = await User.native((err, collection) => {
  collection.eval(query, (err, docs) => { /* ... */ });
});

// ✅ Safe: parameterized query with strict schema validation
const safeQuery = {
  email: req.param('email'),
  status: 'active'
};
const results = await User.find(safeQuery).limit(10);

2. Validate and sanitize all inputs before using them in MongoDB operations

Use explicit validation libraries (e.g., Ajv) and enforce type checks. Never directly interpolate request parameters into aggregation pipelines or query objects that are passed to User.aggregate() or User.native().

// ❌ Unsafe: directly embedding request params into aggregation
const pipeline = req.body.pipeline; // attacker-controlled
const results = await User.aggregate(pipeline);

// ✅ Safe: whitelisted pipeline stages with strict schema validation
const allowedStages = ['$match', '$sort', '$limit'];
const safePipeline = req.body.pipeline
  .filter(stage => allowedStages.includes(Object.keys(stage)[0]))
  .map(stage => {
    const key = Object.keys(stage)[0];
    return { [key]: stage[key] };
  });
const results = await User.aggregate(safePipeline).limit(100);

3. Use Waterline’s built-in protections and avoid raw evaluation

Prefer Waterline query methods over raw collection.eval or JavaScript execution. If you must use native MongoDB driver methods, isolate them behind services that do not accept untrusted template fragments.

// ❌ Unsafe: using native eval with user input
const userCode = `return db.collection('users').find({$where: '${req.query.where}'}).toArray();`;
const results = await User.native((err, collection) => {
  collection.eval(userCode, (err, docs) => { /* ... */ });
});

// ✅ Safe: using Waterline ORM with parameterized conditions
const users = await User.find()
  .where({ status: 'verified' })
  .limit(20);

// If native driver is required, wrap it safely
const docs = await User.getDatastore().manager
  .db.collection('users')
  .find({ status: 'verified' })
  .limit(50)
  .toArray();

4. Enforce principle of least privilege for MongoDB connections

Configure the MongoDB connection in config/connections.js with a user that has minimal required permissions. Avoid using a superuser account for the application, especially when templates and queries are involved.

// config/connections.js
module.exports.connections = {
  mongoDb: {
    adapter: 'sails-mongo',
    url: 'mongodb://appuser:StrongPassword@cluster0.example.com:27017/appdb?authSource=admin',
    // Use a role that only allows read/write on necessary collections
    roles: [{ role: 'readWrite', db: 'appdb' }]
  }
};

Frequently Asked Questions

Can SSTI in Sails lead to direct MongoDB injection even if Waterline is used?
Yes, if user input is interpolated into templates that later influence MongoDB queries—such as dynamic aggregation pipelines or native collection calls—attackers can manipulate query structure. Always validate and avoid eval-like helpers.
Does middleBrick automatically fix SSTI or MongoDB issues found in Sails apps?
No. middleBrick detects and reports these issues with remediation guidance, but it does not fix, patch, or block. Apply the concrete code fixes outlined in the findings to address SSTI and MongoDB-specific risks.