Skip to content
CWE-89A03:2021 – Injection

Prevention — .NET

SqlParameter, and the Entity Framework distinction that decides everything: FromSqlRaw vs FromSqlInterpolated.

The Rule

Use parameterised SqlCommand with SqlParameter, or Entity Framework's LINQ and interpolated-SQL APIs. Never concatenate or String.Format user input into a command.

The .NET-specific trap is Entity Framework Core's pair of raw-SQL methods: FromSqlInterpolated parameterises, FromSqlRaw does not, and they are one word apart.

ADO.NET

C#UserRepository.csVulnerable
// Concatenation and String.Format are both injectable.
var cmd = new SqlCommand(
    "SELECT * FROM Users WHERE Name = '" + name + "'", conn);

var cmd2 = new SqlCommand(
    string.Format("SELECT * FROM Users WHERE Id = {0}", id), conn);

Entity Framework Core

C#Vulnerable
// FromSqlRaw with an interpolated or concatenated string does NOT
// parameterise. The name is the warning.
var users = context.Users
    .FromSqlRaw($"SELECT * FROM Users WHERE Name = '{name}'")
    .ToList();

// ExecuteSqlRaw has the same trap.
context.Database.ExecuteSqlRaw(
    "DELETE FROM Users WHERE Name = '" + name + "'");

Dapper

C#Vulnerable
// Dapper does not parameterise a string you built yourself.
var users = conn.Query<User>(
    "SELECT * FROM Users WHERE Name = '" + name + "'");

Dynamic Identifiers

No parameter binds a column or table name. Allowlist:

private static readonly Dictionary<string,string> Sortable = new()
{
    ["name"] = "Name", ["date"] = "CreatedAt", ["price"] = "Price"
};

var column = Sortable.GetValueOrDefault(userSort, "Id");
var dir = userDir == "desc" ? "DESC" : "ASC";
var sql = $"SELECT * FROM Products ORDER BY {column} {dir}";
// column and dir are values you control, not user text.

Checklist

  • SqlParameter for every value; never concatenate or String.Format.
  • EF Core: FromSqlInterpolated / ExecuteSqlInterpolated, or FromSqlRaw with explicit parameters. Ban bare FromSqlRaw with interpolation in review.
  • Dapper: anonymous parameter objects.
  • Identifiers: allowlist.
  • Turn on the analyzer warnings (CA2100, the EF Core raw-SQL analyzers) and treat them as errors.
  • Set ASP.NET customErrors/UseExceptionHandler so database errors do not reach clients — see Error-Based.
  • Connect with a least-privilege SQL login, never sa — see MSSQL.