SQL InjectionError-Based

Error-Based SQL Injection: Turning Database Errors Into Data

A verbose database error is not just a stack trace — it is an output channel. Error-based SQLi tricks the database into printing the data you want inside its own error message.

SelfSec Team4 min read
Part 3 of 8from theSQL Injectionseries
CAST('ssec-lab' AS integer)

At a glance

CWE-89
Interpreter
SQL database engine
Required condition
An injectable expression can trigger database errors that reach the response.
Potential impact
Schema discovery and sensitive-data disclosure through database error text.
Primary defense
Parameterized queries; generic client errors are only a secondary safeguard.

Safe practice: use benign proof only, in a disposable local lab or on a system you are explicitly authorized to test.

On this page

Blind injection extracts data one bit at a time because the database refuses to talk. Error-based injection is the opposite situation: the database is talking too much. When an application returns detailed SQL errors to the client, those error strings become a high-bandwidth output channel — and an attacker can force the database to embed chosen data inside an error it is guaranteed to raise.

This post covers how verbose errors leak context, how behavior differs across current database versions, why detailed production errors are dangerous, and the two-part fix.

When this technique applies

Error-based confirmation needs both an injectable expression and a path that returns database-controlled text to the client. A generic 500 with no engine detail is not an error-based output channel, although the underlying query may still be injectable through another technique.

The safest proof makes the database include a unique fixed marker in a conversion or parsing error. If the exact marker appears in an engine-specific message, the response contains text generated after SQL evaluation. There is no need to select a table or secret.

How it happens

The setup needs two ingredients: an injectable query, and an application that forwards the database's error text to the response. The second is alarmingly common in default configurations and debug builds:

$id = $_GET['id'];
$result = mysqli_query($db, "SELECT name FROM products WHERE id = $id");

if (!$result) {
    http_response_code(500);
    echo "Database error: " . mysqli_error($db);
}

That mysqli_error($db) is the leak. Whatever the database complains about — including any value the attacker can smuggle into the error — is rendered straight back to them. The attacker's job is now to provoke an error whose message contains the data they want.

A concrete attack: leaking through forced errors

On PostgreSQL, casting a fixed text marker to an integer raises a conversion error that includes the value:

1 AND CAST('ssec-lab' AS integer)=1

The error comes back carrying the harmless marker:

invalid input syntax for type integer: "ssec-lab"

On SQL Server, the same proof uses CONVERT:

1 AND 1=CONVERT(int, 'ssec-lab')
Conversion failed when converting the nvarchar value
'ssec-lab' to data type int.

The application meant to report failure. Instead it returned database-generated text containing a value controlled inside the injected expression.

Per-engine nuances

The primitive and message differ by engine and version. EXTRACTVALUE and UPDATEXML are often shown for legacy MySQL and current MariaDB, but MySQL removed those XML functions in 8.0. Current assessments must fingerprint the actual engine rather than assume an old payload is supported. Conversion, XML, JSON and arithmetic errors can all reveal evaluated values in particular contexts.

The technique depends entirely on errors reaching the client. If the application catches them and returns a generic response, error-based extraction loses its channel. That reduces information exposure but does not repair the injectable query.

Why verbose errors are dangerous

Detailed database errors in production are an information exposure problem even without injection. They can reveal the engine, table or column names, constraint details and query structure. With an injection point, that channel may include values evaluated inside the query. Generic error pages are therefore important hardening, but parameterization remains the control that fixes SQL injection.

The fix: parameterize and suppress detail

Two complementary fixes. First, parameterize so no input can alter the query or reach an error-raising function:

using var cmd = new SqlCommand(
    "SELECT name FROM products WHERE id = @id", connection);
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;

Second, never return raw database errors to clients. Log the detail server-side, show the user a generic message, and set the platform to production mode so stack traces and SQL text are suppressed:

catch (SqlException ex)
{
    logger.LogError(ex, "Query failed for product {Id}", id);
    return Results.Problem("An unexpected error occurred.");
}

Pair this with a least-privilege account so that even a leaked error cannot reach data the query had no business touching.

Signals that are not proof

  • A generic application exception that contains no database-specific evidence.
  • A marker reflected from the request rather than embedded in a database-generated message.
  • A debug error produced before the query executes.
  • One legacy function failing because it does not exist on the deployed engine.
  • A WAF error page that mentions SQL syntax but never reaches the database.

How SelfSec finds it

SelfSec's SQL injection engine covers 19 database families and uses error-based extraction as one of its core techniques. It fingerprints the backend, selects a primitive supported by the detected engine and version — including legacy XML errors where they exist and type-conversion errors on SQL Server — and parses database-generated evidence rather than relying on a reflected marker. The engine validates the evidence before reporting a finding and includes a reproduction request you can replay. Core scan processing runs locally on 127.0.0.1.

References

SelfSec is intended strictly for authorized security testing of systems you own or are explicitly permitted to assess.

Do both things about SQL Injection

SelfSec covers this class from both sides — the scanner confirms it in your own app, the firewall blocks it in front of your origin while the fix ships.

The SQL Injection series

  1. 01OverviewSQL Injection, Explained: From Login Bypass to Full Data Extraction6 min
  2. 02Boolean-Based BlindBoolean-Based Blind SQL Injection: Extracting Data One Bit at a Time4 min
  3. 03Error-BasedError-Based SQL Injection: Turning Database Errors Into DataReading
  4. 04Out-of-BandOut-of-Band SQL Injection: Confirming a Blind Flaw Through DNS5 min
  5. 05Second-OrderSecond-Order SQL Injection: When Stored Input Detonates Later4 min
  6. 06Stacked QueriesStacked Queries: Running Multiple Statements Through One Injection4 min
  7. 07Time-Based BlindTime-Based Blind SQL Injection: Reading a Database Through the Clock5 min
  8. 08UNION-BasedUNION-Based SQL Injection: Appending Your Own Result Set4 min

Related reading