Fix NoSQL Injection in Koa
NoSQL Injection in Koa environments occurs when untrusted input from 'ctx.request.body' or 'ctx.query' is passed directly into database query filters. Since Koa's body-parsers handle JSON objects, an attacker can substitute a string with a nested object containing MongoDB operators like $gt, $ne, or $regex. This allows for authentication bypass, data exfiltration, and logic manipulation. If you aren't sanitizing your input objects, you're leaving the door wide open for database takeover.
The Vulnerable Pattern
const Koa = require('koa'); const Router = require('@koa/router'); const bodyParser = require('koa-bodyparser'); const { MongoClient } = require('mongodb');const app = new Koa(); const router = new Router(); app.use(bodyParser());
// VULNERABLE: Attacker can inject operators via JSON body router.post(‘/api/v1/login’, async (ctx) => { const { username, password } = ctx.request.body;
// If attacker sends {“username”: “admin”, “password”: {“$ne”: ""}}, // the query returns the first user where password is not empty. const user = await ctx.db.collection(‘users’).findOne({ username, password });
if (user) { ctx.body = { status: ‘success’, token: ‘secret_session_token’ }; } else { ctx.status = 401; ctx.body = { error: ‘Unauthorized’ }; } });
The Secure Implementation
To mitigate NoSQL injection in Koa, you must implement two layers of defense. First, use a library like 'mongo-sanitize' to recursively remove any keys starting with '$' from the request object; this prevents operator injection. Second, implement strict type validation. In the secure example, we verify that 'username' and 'password' are primitive strings. This prevents an attacker from passing an object even if it doesn't contain a '$' sign. For larger projects, using a validation schema (like Joi or Zod) to enforce strict input shapes is the gold standard.
const Koa = require('koa'); const Router = require('@koa/router'); const bodyParser = require('koa-bodyparser'); const sanitize = require('mongo-sanitize');const app = new Koa(); const router = new Router(); app.use(bodyParser());
// SECURE: Strict type checking and sanitization router.post(‘/api/v1/login’, async (ctx) => { // 1. Sanitize the entire body to strip any keys starting with $ const cleanBody = sanitize(ctx.request.body);
const { username, password } = cleanBody;
// 2. Enforce type constraints - ensure inputs are strings, not objects if (typeof username !== ‘string’ || typeof password !== ‘string’) { ctx.status = 400; ctx.body = { error: ‘Invalid input types’ }; return; }
const user = await ctx.db.collection(‘users’).findOne({ username: username, password: password });
if (user) { ctx.body = { status: ‘success’ }; } else { ctx.status = 401; } });
Your Koa API
might be exposed to NoSQL Injection
74% of Koa 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.