Latest Intelligence

OWASP Top 10 — #3: Injection

7/13/2026
Research Report

Technical Presentation

OWASP Top 10 — #3: Injection

OWASP Top 10 — A03: Injection

The Complete Zero-to-Hero Guide

Where We Are in the Series

  1. What Is Injection?

Simple definition

Injection happens when an application sends untrusted input to an interpreter as part of a command or query, and the interpreter treats that input as code instead of just data.

That is the heart of injection:

The system cannot properly separate data from instructions.

Real-life analogy

Imagine you go to a restaurant.

The waiter asks:

“What would you like to order?”

A normal customer says:

  • “Chicken soup”
  • “Pasta”
  • “Tea”

But an attacker writes this on the order slip:

  • “Chicken soup, and also unlock the cash register and give me all the money.”

If the kitchen and cashier blindly follow everything on the slip as instructions, the customer just changed the system’s behavior.

That is injection.

Visualizing the core problem

What this diagram means

In a safe system, user input remains just input. In a vulnerable system, attacker input crosses a line and becomes part of the command itself.

That is why injection is so dangerous: the attacker is no longer just “using” your application — they are changing what your application tells another component to do.

  1. The Key Concept: Interpreters

Injection only makes sense if you understand interpreters.

An interpreter is something that reads instructions and executes them.

Common examples:

  • SQL database engine
  • operating system shell
  • browser JavaScript engine
  • LDAP engine
  • XPath engine
  • template engine
  • NoSQL query parser

Important lesson

Injection is not “just SQL injection.”

Injection is a family of vulnerabilities:

  • SQL Injection
  • NoSQL Injection
  • OS Command Injection
  • LDAP Injection
  • XPath Injection
  • XSS (script injection into the browser)
  • Template Injection
  • XML-related injection problems
  1. Why Injection Happens

Injection usually happens because developers do one or more of these things:

In plain English

  • The developer builds commands using strings
  • User input is directly inserted into those strings
  • The system sends that final string to an interpreter
  • The interpreter cannot tell which part is “real code” and which part came from the attacker
  1. The General Anatomy of an Injection Bug

The vulnerable point

The dangerous moment is here:

The application takes user input and builds a command/query string with it.

That is the place where data becomes dangerous.

  1. SQL Injection — The Classic Injection Vulnerability

5.1 What is SQL?

SQL stands for Structured Query Language. Applications use SQL to talk to relational databases like:

  • MySQL
  • PostgreSQL
  • Microsoft SQL Server
  • Oracle
  • SQLite

A query might look like this:

sql
SQLSELECT * FROM users WHERE username = 'alice' AND password = 'secret123';

That means:

Find a row in the users table where username is alice and password is secret123.

5.2 What is SQL Injection?

SQL Injection happens when attacker-controlled input changes the meaning of the SQL query.

Unsafe login example

python
# ❌ Vulnerable example
username = request.form["username"]
password = request.form["password"]

query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
result = db.execute(query)

This looks innocent — but it is dangerous because user input is inserted directly into the SQL string.

Why this is bad

If the attacker provides input that contains SQL syntax, the final query changes.

The application intended to send:

  • “check username and password”

But the attacker may make it send:

  • “check username OR bypass the condition”

The result: authentication bypass, data theft, or worse.

python
# ✅ Safe example
username = request.form["username"]
password = request.form["password"]

query = "SELECT * FROM users WHERE username = ? AND password = ?"
result = db.execute(query, [username, password])

Why this works

With parameterized queries:

  • SQL structure is fixed first
  • user input is passed separately
  • the database treats input as data only
  • attacker input cannot change query structure

5.4 What SQL injection can lead to

In practice, this can mean:

  • logging in as someone else
  • stealing all users
  • changing balances
  • deleting tables
  • dumping customer records
  • learning table names and schema
  • pivoting deeper into the environment

5.5 Blind SQL Injection

Sometimes the app does not show database errors or direct data. That does not mean SQL injection is impossible.

The attacker may still infer truth from behavior:

  • page changes
  • yes/no response
  • time delay
  • different status code

What students should understand

Blind SQL injection teaches a very important lesson:

Even if the app “shows nothing useful,” the attacker may still extract data indirectly.

That is why hiding errors alone is not a fix. You must fix the root cause: unsafe query construction.

  1. NoSQL Injection

Modern apps often use NoSQL databases like:

  • MongoDB
  • CouchDB
  • Firebase-style query layers

Many beginners think:

“We don’t use SQL, so SQL injection is impossible — therefore we are safe.”

That is false.

The syntax may be different, but the core problem is the same:

User input changes query logic.

Example concept

A MongoDB query might expect:

  • username = string
  • password = string

But if the server accepts raw structured input without validation, the attacker may pass objects/operators instead of plain values.

Vulnerable example

javascript
// ❌ Vulnerable Node/Mongo example
app.post('/login', async (req, res) => {
  const user = await db.collection('users').findOne({
    username: req.body.username,
    password: req.body.password
  });

  if (user) {
    res.send("Logged in");
  } else {
    res.send("Denied");
  }
});

Why this can be dangerous

If input is not type-checked and sanitized, the application may accept unexpected structures rather than plain strings.

Safe version

javascript
// ✅ Safer version
app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  if (typeof username !== "string" || typeof password !== "string") {
    return res.status(400).send("Invalid input");
  }

  const user = await db.collection('users').findOne({
    username: username,
    password: password
  });

  if (user) {
    res.send("Logged in");
  } else {
    res.send("Denied");
  }
});

Core lesson

For NoSQL too:

  • validate types
  • validate structure
  • never trust nested operator objects from users
  • use safe query building patterns
  1. OS Command Injection

This is one of the most dangerous forms of injection.

What is it?

The application takes user input and uses it in an operating system command.

For example:

  • ping a host
  • convert an image
  • compress a file
  • run a shell script
  • look up DNS
  • call a system utility

If user input is inserted unsafely, the attacker may execute additional commands.

Real-life analogy

You ask an employee:

“Call this number.”

Instead of giving a number, an attacker gives:

“Call this number, then open the vault, then turn off the cameras.”

If the employee blindly obeys everything, disaster.

Vulnerable flow

Vulnerable example

python
# ❌ Vulnerable
import subprocess

ip = request.args.get("ip")
output = subprocess.check_output(f"ping -c 4 {ip}", shell=True)
return output

Why this is dangerous

  • shell=True means the input is interpreted by the shell
  • shell syntax becomes meaningful
  • attacker input may add extra commands

The application thought it was only running:

  • ping -c 4 8.8.8.8

But it may end up running much more.

python
# ✅ Safer
import subprocess
import re

ip = request.args.get("ip")

if not re.match(r"^\d{1,3}(\.\d{1,3}){3}$", ip):
    return "Invalid IP", 400

output = subprocess.check_output(["ping", "-c", "4", ip], shell=False)
return output

Why this is safer

  • input is validated
  • no shell string concatenation
  • arguments are passed as separate values
  • shell metacharacters do not get interpreted

OS command injection impact

This is why command injection is often considered one of the worst forms of injection.

  1. XSS — Injection into the Browser

In OWASP 2021, XSS is grouped under Injection, which makes sense because it is also a case of:

attacker-controlled input being interpreted as executable code

But here, the interpreter is not the database or shell.

It is the browser.

What is XSS?

XSS stands for Cross-Site Scripting.

It happens when attacker-controlled content is included in a web page in a way that lets the browser treat it as executable JavaScript or HTML rather than plain text.

Three major types

8.1 Reflected XSS

Attacker input comes in the request and is immediately reflected in the response.

Example pattern:

  • search page prints the search term
  • error page prints a parameter
  • message page prints user-controlled text

8.2 Stored XSS

The attacker stores malicious content in the application:

  • comment
  • profile field
  • forum post
  • support ticket
  • chat message

Later, other users load that content and their browsers execute it.

Stored XSS is often more severe than reflected XSS because it can hit many victims automatically.

8.3 DOM-Based XSS

The issue happens entirely in client-side JavaScript.

The server may not even see the malicious transformation. The browser-side code reads untrusted data and injects it unsafely into the DOM.

Vulnerable HTML example

html
<!-- ❌ Vulnerable -->
<div id="welcome"></div>

<script>
  const name = new URLSearchParams(window.location.search).get("name");
  document.getElementById("welcome").innerHTML = "Hello, " + name;
</script>

Why this is dangerous

If name contains HTML/JS-capable content, innerHTML may interpret it as markup.

Safe version

html
<!-- ✅ Safer -->
<div id="welcome"></div>

<script>
  const name = new URLSearchParams(window.location.search).get("name");
  document.getElementById("welcome").textContent = "Hello, " + name;
</script>

Why this is safer

textContent treats the value as text, not as HTML.

XSS impact

  1. Other Injection Families You Should Know

Not every injection type needs a huge section, but students should know they exist.

LDAP Injection

Unsafe user input changes LDAP search filters.

XPath Injection

Unsafe input changes XML query logic.

Template Injection

Unsafe data reaches template expressions and may lead to server-side code execution.

SMTP Header Injection

Unsafe input alters email headers, recipients, or mail behavior.

The common pattern is always the same:

untrusted input is interpreted in a powerful context
  1. Root Causes of Injection, Deeply Explained

Let’s simplify injection down to its root causes.

10.1 Mixing code and data

This is the universal root cause.

10.2 Unsafe APIs

Some APIs make unsafe behavior easy.

Examples:

  • dynamic SQL string building
  • shell execution with string commands
  • innerHTML
  • dangerous template rendering
  • generic eval-like functions

10.3 Weak or missing validation

Validation does not replace parameterization, but it still matters.

For example:

  • IP addresses should look like IPs
  • email fields should look like emails
  • sort order should be from an allowlist like asc or desc
  • IDs should be numeric or UUIDs as expected

10.4 Wrong output handling

For XSS especially, the problem often is not the input alone — it is the output context.

Different contexts need different protection:

  • HTML body
  • HTML attribute
  • JavaScript string
  • CSS
  • URL
  • SQL parameter
  • shell argument

There is no single universal “escape everything” function that solves all contexts.

That is why security teams talk about context-aware encoding.

  1. Prevention Strategy — The Big Picture

The Golden Rule

Never let untrusted input define interpreter structure.

11.1 Prevention map

11.2 Parameterize everything that can be parameterized

This applies to:

  • SQL
  • NoSQL where supported through safe abstractions
  • LDAP filters where safe APIs exist
  • OS commands via argument arrays
  • template values via safe rendering methods

11.3 Use allowlists, not vague assumptions

Bad mindset:

  • “Users probably won’t enter weird input”

Good mindset:

  • “Users can send anything. I will explicitly define what is acceptable.”

Examples:

  • country code must be from known list
  • sort field must be from allowlist
  • ID must be integer/UUID
  • file type must be from strict allowed set

11.4 Escape or encode for the right context

For XSS, use:

  • framework auto-escaping
  • textContent instead of innerHTML
  • safe templating
  • HTML encoding
  • attribute encoding
  • JavaScript-safe serialization where needed

11.5 Least privilege

If injection happens, damage should still be limited.

Examples:

  • app DB user should not be DB admin
  • app OS user should not be root
  • service accounts should have minimum permissions
  • cloud roles should be tightly scoped

1.6 Content Security Policy for XSS impact reduction

CSP does not fix XSS root causes, but it can reduce damage.

A strict CSP can:

  • block inline scripts
  • restrict script sources
  • reduce data exfiltration options
  • make exploitation harder

Example:

sh
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';
  1. Testing for Injection

You should test injection risks systematically.

Questions to ask during review

  • Does this input go into SQL?
  • Does this input go into a shell command?
  • Does this input end up in HTML?
  • Does this input reach a template engine?
  • Does this input get used in LDAP/XPath filters?
  • Is code/data separation guaranteed?
  • Is the escaping correct for this specific context?
  1. A Mental Model for Students

Whenever you see input, ask this:

code
One-View Cheat Sheet
Injection Type	Target	Main Risk	Best Defense
SQL Injection	SQL database	auth bypass, data theft, data destruction	parameterized queries
NoSQL Injection	NoSQL DB	logic bypass, data exposure	strict type/structure validation
OS Command Injection	shell / system	remote command execution	avoid shell, use safe argument arrays
Reflected XSS	browser	script execution in victim browser	output encoding
Stored XSS	browser/users	mass client-side compromise	sanitize/encode output, safe rendering
DOM XSS	browser DOM	client-side code execution	safe DOM APIs like textContent
LDAP/XPath Injection	directory/XML query	unauthorized lookup/access	safe query APIs + validation
Template Injection	template engine	server-side execution	safe rendering, no untrusted expressions

The Most Important Lesson

If user input can change structure, you are in danger. If user input is treated only as data, you are much safer.