NoSQL and ORM Injection
SQL injection techniques extend beyond traditional SQL databases to NoSQL databases and Object-Relational Mappers (ORMs).
NoSQL Injection
NoSQL databases like MongoDB are vulnerable to injection attacks through operator manipulation.
MongoDB Operator Injection
Vulnerable authentication check:
// Vulnerable code
db.users.find({
username: req.body.username,
password: req.body.password,
});
Malicious payload:
{
"username": { "$ne": null },
"password": { "$ne": null }
}
This matches any document where username and password exist, bypassing authentication.
JavaScript Injection in $where
// Vulnerable query using $where
db.users.find({ $where: "this.username == '" + username + "'" });
// Malicious input: ' || '1'=='1
// Becomes: this.username == '' || '1'=='1'
Prevention for NoSQL
// Use mongo-sanitize library
const sanitize = require('mongo-sanitize');
const cleanUsername = sanitize(req.body.username);
// Enforce explicit operators
db.users.find({
username: { $eq: username },
});
// Disable JavaScript execution
// mongod --noscripting
ORM Injection
ORM layers can be vulnerable when developers bypass the ORM's protections.
Vulnerable Patterns
Rails ActiveRecord (vulnerable):
# DON'T DO THIS - vulnerable to injection
Orders.find_all(
"customer_id = 123 AND order_date = '#{params[:order_date]}'"
)
# SAFE - parameterized
Orders.where(
"customer_id = ? AND order_date = ?",
customer_id, order_date
)
Django ORM (vulnerable):
# DON'T DO THIS - vulnerable
User.objects.raw(f"SELECT * FROM users WHERE username = '{username}'")
# SAFE - ORM query
User.objects.filter(username=username)
Hibernate HQL (vulnerable):
// DON'T DO THIS - vulnerable
session.createQuery("from Orders where id = " + orderId)
// SAFE - positional parameters
session.createQuery("from Orders where id = ?1")
.setParameter(1, orderId)
SQLAlchemy (vulnerable):
# DON'T DO THIS - vulnerable
session.execute(f"SELECT * FROM users WHERE id = {user_id}")
# SAFE - parameterized
session.execute(text("SELECT * FROM users WHERE id = :id"), {"id": user_id})
Recent ORM Vulnerabilities (2020-2024)
| CVE | Framework | Issue |
|---|---|---|
| CVE-2024-42005 | Django | JSON field SQL injection |
| CVE-2023-22794 | Rails ActiveRecord | Injection via accepts_nested_attributes |
| CVE-2020-25638 | Hibernate | Criteria API injection |
Best Practices for ORMs
- Avoid raw SQL methods when possible
- Keep ORM libraries updated - security patches are released regularly
- Never concatenate user input into queries
- Use parameterized queries even within ORM raw methods
- Review generated SQL during development
Command Injection via SQL
Attackers can escalate SQL injection to execute operating system commands.
xp_cmdshell (MS SQL Server)
-- Enable xp_cmdshell (requires admin)
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
-- Execute commands
EXEC xp_cmdshell 'net user';
EXEC xp_cmdshell 'whoami';
INTO OUTFILE (MySQL)
-- Write webshell to server
SELECT '<?php system($_GET["cmd"]); ?>'
INTO OUTFILE '/var/www/html/shell.php';
-- Read sensitive files
LOAD DATA INFILE '/etc/passwd' INTO TABLE temp_table;
Prevention
- Disable
xp_cmdshellwhen not needed - Set
secure_file_privto restrict file operations in MySQL - Run database services under limited-privilege accounts
- Never expose sysadmin credentials to web applications
How Oxide SQL Helps
Oxide SQL prevents ORM-like injection vulnerabilities by enforcing parameterization at the type level. The type system prevents unsafe string concatenation, and there is no way to inject raw SQL -- the builder API only accepts structured components. Unlike ORMs that provide "escape hatches" for raw SQL, Oxide SQL's builder pattern makes injection impossible through its API design.
See the builder module rustdoc for examples.