Fix SQL Injection (Legacy & Modern) in Koa
SQL Injection in Koa is a classic failure of input sanitization and query construction. When you allow raw user input from 'ctx.request.body' or 'ctx.query' to be concatenated directly into your SQL strings, you're handing over your database keys to any script kiddie with a copy of sqlmap. In modern Node.js environments, there is zero excuse for this. You either use parameterized queries or a type-safe ORM/Query Builder that handles bindings for you.
The Vulnerable Pattern
const Koa = require('koa'); const bodyParser = require('koa-bodyparser'); const mysql = require('mysql2/promise'); const app = new Koa(); app.use(bodyParser());
app.use(async (ctx) => { if (ctx.path === ‘/login’ && ctx.method === ‘POST’) { const { username, password } = ctx.request.body; const db = await mysql.createConnection(config); // VULNERABLE: Template literals allow an attacker to escape the query // Payload: admin’ — const [rows] = await db.execute(SELECT * FROM users WHERE user = '${username}' AND pass = '${password}'); ctx.body = rows; } });
The Secure Implementation
The fix relies on 'Prepared Statements'. By using placeholders (?), the database driver sends the SQL template and the data in two separate steps. The database engine parses the query logic first, then treats the user-provided parameters strictly as literal data. Even if the 'username' contains SQL commands like 'DROP TABLE', it is treated as a harmless string. For modern Koa apps, it is highly recommended to use a Query Builder like Knex.js (e.g., knex('users').where({ user: username })) or an ORM like Prisma, which implement these protections by default.
const Koa = require('koa'); const bodyParser = require('koa-bodyparser'); const mysql = require('mysql2/promise'); const app = new Koa(); app.use(bodyParser());
app.use(async (ctx) => { if (ctx.path === ‘/login’ && ctx.method === ‘POST’) { const { username, password } = ctx.request.body; const db = await mysql.createConnection(config); // SECURE: Parameterized queries (Prepared Statements) // The ’?’ acts as a placeholder; data is sent separately from the command const [rows] = await db.execute(‘SELECT * FROM users WHERE user = ? AND pass = ?’, [username, password]); ctx.body = rows; } });
Your Koa API
might be exposed to SQL Injection (Legacy & Modern)
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.