Server Side Template Injection in Hapi with Mongodb
Server Side Template Injection in Hapi with Mongodb — how this specific combination creates or exposes the vulnerability
Server Side Template Injection (SSTI) in a Hapi application using MongoDB can occur when user-controlled data is embedded into a template string that is later interpreted by a template engine. Hapi does not include a built-in template engine, but integrations such as @hapi/inert or custom rendering layers often pass request parameters into templates. If those parameters are not validated or escaped, an attacker can inject template directives that cause the engine to execute unintended logic.
When templates are rendered and combined with MongoDB operations, injection can lead to unintended query behavior. For example, if a template variable is used to construct a MongoDB query object without proper sanitization, an attacker may manipulate the structure of the query. This can result in data exfiltration, bypassing intended filters, or reading more data than the application intends. The risk is higher when the template engine supports JavaScript-like expressions, because an attacker may attempt to break out of the intended context and interact directly with the database layer.
Consider an endpoint that renders a user profile page and simultaneously queries MongoDB based on a template variable. If the template injection payload modifies the query structure, the backend might expose documents that should remain private. Because Hapi typically does not enforce strict separation between route handlers and template context, developers must explicitly validate and sanitize all inputs that flow into templates and subsequent database calls. The combination of a flexible template engine and a schemaless database like MongoDB increases the potential impact of injection, as malicious data can reshape query logic in ways that are not immediately obvious.
Real-world scenarios often involve indirect injection where the template does not directly touch MongoDB but alters control flow in a way that affects which database operations are performed. For instance, an injected expression might change which collection is queried or which filters are applied. Because MongoDB queries are expressed as JSON-like documents, tampering with keys or values through template injection can lead to unexpected match conditions or even command-like behaviors if the application dynamically builds pipelines or uses evaluation features.
middleBrick detects such issues by analyzing the unauthenticated attack surface and correlating runtime behavior with OpenAPI specifications, including $ref resolution. The scanner checks whether template-related inputs reach data access layers and whether the API schema exposes endpoints that could amplify injection risks. Findings include severity ratings and remediation guidance to help developers break the injection path between templates and MongoDB queries.
Mongodb-Specific Remediation in Hapi — concrete code fixes
To prevent SSTI when using MongoDB in Hapi, ensure strict separation between data and commands. Never concatenate or interpolate user input directly into MongoDB query objects or template strings. Use parameterized queries and explicit schema validation. The following examples illustrate secure patterns.
1. Use a whitelist approach for template variables and avoid evaluating expressions that can reach database logic. With inert, pass only pre-sanitized context:
// Safe: user input is not used to build query objects
const sanitizedName = validateAlphanumeric(req.query.name);
const query = { username: sanitizedName };
const user = await db.collection('users').findOne(query);
const context = {
username: user ? user.username : 'Guest',
features: await getFeatures()
};
const html = await inert.renderTemplate('profile.html', context);
return reply.view('profile', context);
2. Validate and cast inputs before using them in aggregation pipelines or query stages. Do not allow template variables to dictate stage names or operators:
// Safe: pipeline stages are hardcoded; user input only affects values
const matchStage = { $match: { email: req.query.email } };
// Incorrect: const pipeline = [req.query.stage]; // Never do this
const pipeline = [matchStage, { $project: { name: 1, email: 1 } }];
const results = await db.collection('users').aggregate(pipeline).toArray();
3. Apply schema validation at the API boundary and enforce allowlists for fields that can influence query construction. Use Joi or another validator to ensure only expected keys and types reach MongoDB:
const schema = Joi.object({
email: Joi.string().email().required(),
limit: Joi.number().integer().min(1).max(100).default(10)
});
const { error, value } = schema.validate(req.query);
if (error) {
return reply.badRequest('Invalid parameters');
}
const cursor = db.collection('users').find({ email: value.email }).limit(value.limit);
4. If you must use dynamic field names, map them through a strict dictionary instead of trusting raw input:
const allowedFields = { username: 1, email: 1, createdAt: 1 };
const sortBy = allowedFields[req.query.sortBy] ? req.query.sortBy : 'createdAt';
const cursor = db.collection('users').find({}).sort({ [sortBy]: 1 });
5. For applications using templating with dynamic includes or partials, ensure that template names are resolved from a fixed set and not derived from user data:
const allowedTemplates = { profile: 'profile.html', settings: 'settings.html' };
const templateName = allowedTemplates[req.query.tpl] || 'profile.html';
const html = await inert.renderTemplate(templateName, context);
middleBrick’s scans include checks that verify whether endpoints expose MongoDB-related operations and whether template-related inputs flow into data access layers. By running the CLI or adding the GitHub Action to your CI/CD pipeline, you can automatically detect risky patterns before deployment. The Pro plan provides continuous monitoring so that regressions are caught early, and findings are mapped to frameworks such as OWASP API Top 10 and SOC2.