Fix NoSQL Injection in Hapi
NoSQL Injection in Hapi typically occurs when raw user input from 'request.payload', 'request.params', or 'request.query' is passed directly into a database filter. In Node.js ecosystems using MongoDB or Mongoose, attackers exploit the lack of type enforcement to inject operator objects like '{$gt: ""}' or '{$ne: null}'. This allows for authentication bypass, data exfiltration, and logic manipulation. If your route handlers don't validate that inputs are strings rather than objects, your database is an open book.
The Vulnerable Pattern
server.route({
method: 'POST',
path: '/api/login',
handler: async (request, h) => {
const { username, password } = request.payload;
// VULNERABLE: If payload is { "username": "admin", "password": { "$ne": "" } },
// the query becomes User.findOne({ username: 'admin', password: { $ne: '' } })
// effectively logging in as admin without a password.
const user = await User.findOne({ username, password });
if (!user) return h.response({ error: 'Unauthorized' }).code(401);
return { success: true };
}
});
The Secure Implementation
The primary defense against NoSQL injection in Hapi is leveraging its built-in validation engine, Joi. The vulnerability stems from type confusion: the database driver accepts both strings and objects. By defining a strict Joi schema in the route's 'options.validate' block, you ensure that incoming data matches expected types. When Joi specifies 'Joi.string()', any attempt to pass a MongoDB operator object will fail validation. This 'Secure by Design' approach stops the attack at the framework level before the malicious payload ever reaches your database logic.
const Joi = require('joi');
server.route({ method: ‘POST’, path: ‘/api/login’, options: { validate: { // SECURE: Joi enforces that ‘username’ and ‘password’ MUST be strings. // If an attacker sends an object, Hapi returns a 400 Bad Request before the handler runs. payload: Joi.object({ username: Joi.string().min(3).max(30).required(), password: Joi.string().required() }), failAction: (request, h, err) => { throw err; } } }, handler: async (request, h) => { const { username, password } = request.payload; const user = await User.findOne({ username, password }); if (!user) return h.response({ error: ‘Unauthorized’ }).code(401); return { success: true }; } });
Your Hapi API
might be exposed to NoSQL Injection
74% of Hapi apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.