DEV Community

Injection Attacks Are Not Dead: SQL, NoSQL, ORM, and Command Injection — How to Actually Fix Them (2026)

Mahdi Shamlou here.

“Mahdi, I finally launched my e‑commerce site. And don’t worry — I used MongoDB, so no SQL injection. You can’t hack it.”

I laughed. Then I asked him to let me try.

Within 10 minutes, I bypassed his login with a NoSQL injection and pulled out his entire user collection. His face went pale.

Moral of the story: “No SQL” does NOT mean “no injection”. Injection is a whole class of attacks — SQL, NoSQL, ORM, command, LDAP, you name it. If you concatenate user input into any kind of query or system command, you’re likely vulnerable.

In this guide, I’ll show you:

  • How I hacked my friend’s NoSQL login (and how to fix it).
  • Classic SQL injection — still alive and well.
  • How even an ORM like SQLAlchemy can betray you if you misuse it.
  • Command injection that gives attackers a shell on your server.
  • Actual code fixes + tools to find these bugs automatically.

Let’s dive in.


Mahdi Shamlou

The Story: “But I Use NoSQL! (And Why That’s Not Enough)

My friend’s site had a simple login form like this:


// Node.js + Express + MongoDB
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  db.collection('users').findOne({
    username: username,
    password: password
  }, (err, user) => {
    if (user) res.send('Logged in');
    else res.send('Invalid credentials');
  });
});
Enter fullscreen mode Exit fullscreen mode

He thought: “No SQL strings, no injection.

I sent this JSON as the username:


{ "username": { "$ne": null }, "password": { "$ne": null } }

Enter fullscreen mode Exit fullscreen mode

MongoDB interpreter turned it into:


db.users.findOne({
  username: { $ne: null },
  password: { $ne: null }
})
Enter fullscreen mode Exit fullscreen mode

That returns the first user — no password check needed. I was in.

Lesson: Any system that interprets user input as a command (SQL, JavaScript, shell, etc.) can be injected. NoSQL is no exception.


A03: Injection (The Unified Monster)

OWASP ranks Injection as #3 in 2026 (and #1 in many earlier lists). The root cause is the same:

Untrusted data is sent to an interpreter as part of a command or query.

Check this : OWASP Top 10 for Developers (2026 Edition) — How to Actually Fix the Most Dangerous Web Vulnerabilities

We’ll cover the most dangerous flavours.


1. SQL Injection — The Old King

Still #1 in bug bounties.
Vulnerable Code (Python/Flask)


@app.route('/user')
def get_user():
    user_id = request.args.get('id')
    query = f"SELECT * FROM users WHERE id = {user_id}"   # 😱
    cursor.execute(query)
    return cursor.fetchone()
Enter fullscreen mode Exit fullscreen mode

Input: ?id=1 UNION SELECT username, password FROM admins --
The Fix — Parameterized Queries


@app.route('/user')
def get_user():
    user_id = request.args.get('id')
    cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
    # Or use an ORM (correctly!)
Enter fullscreen mode Exit fullscreen mode

Tool: sqlmap — automated detection and exploitation.


2. NoSQL Injection — The Modern Trap

MongoDB, CouchDB, etc. are vulnerable when you pass user input directly into query objects.

Vulnerable (Node.js + Mongoose)

User.findOne({ email: req.body.email, password: req.body.password });
Enter fullscreen mode Exit fullscreen mode

Attackers send:

{ "email": { "$regex": ".*" }, "password": { "$ne": "" } }
Enter fullscreen mode Exit fullscreen mode

That matches any email and a non‑empty password → login bypass.

Even worse: $where clauses execute JavaScript.

// Vulnerable
User.find({ $where: `this.name == '${req.body.name}'` });
// Attacker: 'a'; sleep(5000); //
Enter fullscreen mode Exit fullscreen mode

The Fix — Schema Validation + Type Casting


// Use Mongoose schemas with required types
const userSchema = new Schema({
  email: { type: String, required: true },
  password: { type: String, required: true }
});

// And sanitize operators
function sanitizeNoSQL(obj) {
  if (typeof obj !== 'object') return obj;
  const unsafe = ['$where', '$ne', '$gt', '$regex', '$expr'];
  for (let key of unsafe) if (key in obj) delete obj[key];
  return obj;
}

// Then use it
const query = sanitizeNoSQL(req.body);
User.findOne(query);
Enter fullscreen mode Exit fullscreen mode

Better yet: use an allowlist for fields and reject any input with $ or { operators.

Tool: NoSQLMap — automated NoSQL injection


3. ORM Injection — Yes, Even SQLAlchemy

ORMs (SQLAlchemy, Hibernate, Entity Framework) protect you if you use them correctly. But as soon as you write raw SQL or use unsafe methods, you’re back to square one.

Vulnerable SQLAlchemy (Python)

from sqlalchemy import text

@app.route('/search')
def search():
    keyword = request.args.get('q')
    query = text(f"SELECT * FROM products WHERE name LIKE '%{keyword}%'")
    results = db.session.execute(query)
    # Ouch — raw string concatenation inside text()
Enter fullscreen mode Exit fullscreen mode

Attacker: ?q=' OR '1'='1' UNION SELECT ...

Fix — Use ORM Parameters or Bind Variables

# Method 1: ORM safe filtering
from sqlalchemy import or_
products = Product.query.filter(Product.name.ilike(f"%{keyword}%")).all()

# Method 2: If you must use raw SQL, use bind params
query = text("SELECT * FROM products WHERE name LIKE :kw")
results = db.session.execute(query, {"kw": f"%{keyword}%"})
Enter fullscreen mode Exit fullscreen mode

Rule: Never use text() with f‑strings or string concatenation. Always pass parameters as a dict or tuple.

Tool: SQLAlchemy’s own logging — watch for generated queries with suspicious input.


4. Command Injection — Full Server Takeover

When your app calls operating system commands with user input, the attacker can run any command.
Vulnerable (Python)

import subprocess

@app.route('/ping')
def ping():
    ip = request.args.get('ip')
    result = subprocess.check_output(f"ping -c 4 {ip}", shell=True)
    return result
Enter fullscreen mode Exit fullscreen mode

Attacker: ?ip=8.8.8.8; cat /etc/passwd
Fix — Use Native APIs, Avoid Shell=True

import shlex

@app.route('/ping')
def ping():
    ip = request.args.get('ip')
    # Allowlist allowed characters
    if not re.match(r'^[\d\.]+$', ip):
        abort(400)
    # Use list form + no shell
    result = subprocess.check_output(["ping", "-c", "4", ip])
    return result
Enter fullscreen mode Exit fullscreen mode

Even better: Don’t call system commands at all — use native network libraries (e.g., ping3 for Python).

Tool: Commix — automated command injection.


Injection Prevention — A Unified Checklist

Injection Type Prevention Strategy
SQL Parameterized queries / prepared statements (never concatenation).
NoSQL Validate input types, reject operator keys ($), use schema validation.
ORM Avoid raw SQL; use ORM’s safe methods; parameterize any text() call.
Command Use native APIs, avoid shell=True, allowlist inputs.
LDAP Escape special characters (*, (, ), \).
XML/XPath Disable external entities, use hard‑coded XPaths.

Universal Rules

  1. Treat all user input as dangerous.
  2. Use allowlists (e.g., re.match(r'^[a-z0-9]+$', input)).
  3. Prefer safe APIs — ORMs, parameterised queries, native libraries.
  4. Never trust “I don’t use SQL” — injection is about interpreters, not just SQL.

Tools to Find Injection Flaws Automatically

Run these before an attacker does:

  • sqlmap — SQL injection detection & exploitation.
  • NoSQLMap — NoSQL injection (MongoDB, CouchDB).
  • Commix — Command injection.
  • Burp Suite Scanner — All kinds of injection (paid but worth it).
  • OWASP ZAP — Free, includes injection tests.
  • Semgrep or CodeQL — Find injection patterns in your source code.

Hands‑On Practice (Don’t Just Read)

You learn injection by doing it (safely).

Remember my sandbox advice from last article: Run all vulnerable apps inside isolated VMs or Docker containers. Even your own testing can go wrong.


Want More?

If you enjoyed this deep dive into injection attacks, check out:


Mahdi Shamlou

🔗 LinkedIn:
https://www.linkedin.com/in/mahdi-shamlou-3b52b8278
📱 Telegram:
https://telegram.me/mahdi0shamlou
📸 Instagram:
https://www.instagram.com/mahdi0shamlou/

Author: Mahdi Shamlou | مهدی شاملو

Top comments (0)