SecLab
Injection & Output EncodingwalkthroughDifficulty 3/524 min

The escape hatches your ORM still leaves open

Objective: After this lesson you know exactly which EF Core APIs still take raw SQL, and a test that fences them off.

V1CWE-89A05:2025sql-injection
Step 1 of 5 · read5 min

"We use an ORM, so we do not have SQL injection"

That sentence is nearly right, and the "nearly" is the part worth learning.

EF Core parameterises every LINQ query. There is no way to write _db.Users.Where(u => u.Email == email) and get injection — the value always becomes a parameter. If 100% of your queries are LINQ, the sentence is true.

The problem is that 100% never happens, for three entirely reasonable reasons:

  1. Some queries LINQ cannot express — window functions, recursive CTEs, INSERT ... ON CONFLICT, full-text search.
  2. Some queries LINQ can express but translates badly — and somebody measured, then rewrote it in raw SQL.
  3. Somebody pasted a query from pgAdmin into the code because it already worked there.

So the right question is not "do we use an ORM" but "which of the ORM's escape hatches are in use, and who re-reads them".

The EF Core escape-hatch list — this is the one worth pinning to a wall:

APIParameterises automatically?
FromSqlInterpolated, ExecuteSqlInterpolatedYes — interpolated values become parameters
FromSql (EF 7+, takes a FormattableString)Yes — same mechanism
FromSqlRaw, ExecuteSqlRawNo — the string goes in verbatim
Database.GetDbConnection() + CommandTextNo — raw ADO.NET
EF.Functions.Like with a concatenated patternParameterised, but the pattern can be a logic injection
Dapper Query<T>("... " + x)No — Dapper is not a SQL-generating ORM

The subtlest trap is between the first two rows and the third: FromSqlInterpolated($"...{x}") is safe, FromSqlRaw($"...{x}") is not — and the two differ by three characters. This is where a test is worth more than a convention.

View path

Comments

Join the discussion
Sign up to comment

Commenting needs an account with at least one completed lesson. That condition is what keeps this thread worth reading: every point belongs to someone who can be asked back, and reputation accrues over time.

Sign upSign in

You can still read every comment below without an account. Signing in brings you back to this exact spot, not to the top of the page.

Loading comments…