CodeRaptor
Back to Security Vulnerabilities
Critical Severity - OWASP Top 10

SQL Injection

SQL injection is a code injection technique that exploits vulnerabilities in database queries by inserting malicious SQL statements into application input fields. Ranked as OWASP Top 10 A03:2021 (Injection), SQL injection remains one of the most dangerous and prevalent web application vulnerabilities. Attackers can bypass authentication, extract sensitive data, modify or delete records, execute administrative operations, and in severe cases, gain complete control over the database server.

What Is SQL Injection?

SQL injection occurs when user input is inserted directly into SQL queries without proper sanitization or parameterization. The vulnerability arises from the failure to separate code from data, allowing attackers to alter the structure and logic of SQL queries. Common attack vectors include:

Bypass authentication and login as any user (admin privileges)
Extract sensitive data from any table in the database
Modify or delete database records (data manipulation)
Execute administrative operations (DROP, ALTER, CREATE)
Read files from the server filesystem (LOAD_FILE, xp_cmdshell)
Execute commands on the operating system (complete server takeover)
Perform denial-of-service attacks (resource exhaustion)
Pivot to internal network systems (lateral movement)

Types of SQL Injection Attacks

Classic SQL Injection

Critical

Direct injection where error messages reveal database structure. Attacker sees immediate results.

' OR '1'='1

Blind SQL Injection

Critical

No error messages displayed. Attacker infers data by observing application behavior (true/false responses).

' AND 1=1 -- (true) vs ' AND 1=2 -- (false)

Time-Based Blind

High

Infer data by measuring response time differences using database sleep functions.

'; IF (1=1) WAITFOR DELAY '00:00:05' --

UNION-Based Injection

Critical

Use UNION operator to combine results from malicious queries with legitimate query results.

' UNION SELECT username, password FROM users --

Stacked Queries

Critical

Execute multiple SQL statements by terminating the original query and appending new ones.

'; DROP TABLE users; --

Second-Order Injection

High

Malicious data stored safely initially, but executed unsafely in a different context later.

Stored username: admin'-- used in later query

Vulnerable vs Secure Code

Authentication Bypass

Vulnerable - String Concatenation
// DANGEROUS: Direct string concatenation
function loginUser(username, password) {
  const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
  return db.execute(query);
}

// Attack: username = "admin' --"
// Result: SELECT * FROM users WHERE username = 'admin' --' AND password = ''
// The -- comments out the password check, bypassing authentication!
Secure - Parameterized Queries
// SAFE: Using parameterized queries
function loginUser(username, password) {
  const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
  return db.execute(query, [username, password]);
}

// Or with named parameters (e.g., Node.js with pg)
function loginUser(username, password) {
  const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
  return db.query(query, [username, password]);
}

// Attack attempts are treated as literal strings, not SQL code

Data Extraction

Vulnerable - Dynamic Query Building
// DANGEROUS: Building queries with user input
function searchProducts(searchTerm) {
  const query = "SELECT * FROM products WHERE name LIKE '%" + searchTerm + "%'";
  return db.execute(query);
}

// Attack: searchTerm = "' UNION SELECT username, password, NULL FROM users --"
// Result: Extracts all usernames and passwords from users table
Secure - ORM or Prepared Statements
// SAFE: Using ORM (Sequelize example)
async function searchProducts(searchTerm) {
  return await Product.findAll({
    where: {
      name: {
        [Op.like]: `%${searchTerm}%`
      }
    }
  });
}

// Or with prepared statement
function searchProducts(searchTerm) {
  const query = 'SELECT * FROM products WHERE name LIKE ?';
  return db.execute(query, [`%${searchTerm}%`]);
}

Sequelize ORM (Node.js)

Vulnerable - Raw Queries
// DANGEROUS: Using raw queries with string concatenation
async function getUser(userId) {
  const [results] = await sequelize.query(
    `SELECT * FROM users WHERE id = ${userId}`
  );
  return results;
}

// Attack: userId = "1 OR 1=1" exposes all users
Secure - Model Methods & Replacements
// SAFE: Using Sequelize model methods
async function getUser(userId) {
  return await User.findOne({ where: { id: userId } });
}

// Or with raw queries using replacements
async function getUser(userId) {
  const [results] = await sequelize.query(
    'SELECT * FROM users WHERE id = :userId',
    {
      replacements: { userId },
      type: QueryTypes.SELECT
    }
  );
  return results[0];
}

TypeORM (TypeScript)

Vulnerable - Raw Query Building
// DANGEROUS: String concatenation in query builder
async function searchUsers(searchTerm: string) {
  return await dataSource.query(
    `SELECT * FROM users WHERE username LIKE '%${searchTerm}%'`
  );
}

// Attack: searchTerm = "%'; DROP TABLE users; --"
Secure - Query Builder with Parameters
// SAFE: Using TypeORM query builder
async function searchUsers(searchTerm: string) {
  return await userRepository
    .createQueryBuilder('user')
    .where('user.username LIKE :searchTerm', {
      searchTerm: `%${searchTerm}%`
    })
    .getMany();
}

// Or with find options
async function searchUsers(searchTerm: string) {
  return await userRepository.find({
    where: { username: Like(`%${searchTerm}%`) }
  });
}

Prisma ORM (TypeScript)

Vulnerable - Raw SQL
// DANGEROUS: $queryRaw with template literals
async function getProductsByCategory(category: string) {
  return await prisma.$queryRaw`
    SELECT * FROM products WHERE category = '${category}'
  `;
}

// Attack: category = "'; DELETE FROM products; --"
Secure - Prisma Client & Parameters
// SAFE: Using Prisma Client (automatically parameterized)
async function getProductsByCategory(category: string) {
  return await prisma.product.findMany({
    where: { category }
  });
}

// Or with $queryRaw using Prisma.sql (safe interpolation)
async function getProductsByCategory(category: string) {
  return await prisma.$queryRaw`
    SELECT * FROM products WHERE category = ${category}
  `;
  // Prisma automatically parameterizes tagged template values
}

Dynamic ORDER BY & Column Names

Vulnerable - String Interpolation
// DANGEROUS: Dynamic ORDER BY
function getUsers(sortColumn, sortOrder) {
  const query = `SELECT * FROM users ORDER BY ${sortColumn} ${sortOrder}`;
  return db.execute(query);
}

// Attack: sortColumn = "1; DROP TABLE users; --"
// Could delete the entire users table!
Secure - Whitelist Validation
// SAFE: Whitelist allowed columns
function getUsers(sortColumn, sortOrder) {
  const allowedColumns = ['id', 'name', 'email', 'created_at'];
  const allowedOrders = ['ASC', 'DESC'];

  if (!allowedColumns.includes(sortColumn)) {
    throw new Error('Invalid sort column');
  }
  if (!allowedOrders.includes(sortOrder.toUpperCase())) {
    throw new Error('Invalid sort order');
  }

  // Now safe to use in query (column name can't be parameterized)
  const query = `SELECT * FROM users ORDER BY ${sortColumn} ${sortOrder}`;
  return db.execute(query);
}

Prevention Methods

Parameterized Queries

Critical

Always use ? or $1 placeholders instead of string concatenation

ORM/Query Builders

Recommended

Use Sequelize, TypeORM, Prisma, or similar tools that handle escaping

Input Validation

Critical

Validate and sanitize all user inputs before use

Whitelist Approach

Critical

For dynamic parts (ORDER BY, column names), use whitelisting

Least Privilege

High

Database users should have minimal required permissions

Stored Procedures

Medium

Use stored procedures with parameterized inputs

WAF Protection

Medium

Deploy Web Application Firewall to detect SQL injection attempts

Regular Audits

High

Scan code regularly for SQL injection vulnerabilities

Real-World Impact

2023

MOVEit Transfer SQL injection affected 2,000+ organizations

Impact: 77M+ records compromised

2022

Cockroach Labs SQL injection in their cloud platform

Impact: Access to customer data

2019

Capital One breach via SQL injection

Impact: 100M+ customer records stolen

How CodeRaptor Detects SQL Injection

CodeRaptor automatically scans for SQL injection vulnerabilities in pull requests, identifying dangerous patterns before they reach production.

Detects string concatenation in SQL queries
Identifies missing parameterization
Flags dynamic query construction
Checks ORM usage patterns
Validates input sanitization
Suggests secure alternatives
Try CodeRaptor Free