Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,24 @@ private class ExternalSqlInjectionSanitizer extends Sanitizer {
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }

private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }

/**
* A sanitizer for Entity Framework Core's interpolated SQL methods.
* Methods like `FromSqlInterpolated` and `ExecuteSqlInterpolated` accept
* `FormattableString` parameters and properly parameterize interpolated values,
* making them safe from SQL injection.
*/
private class EfCoreInterpolatedSanitizer extends Sanitizer {
EfCoreInterpolatedSanitizer() {
exists(MethodCall mc |
mc.getTarget().getName() in [
"FromSqlInterpolated", "ExecuteSqlInterpolated", "ExecuteSqlInterpolatedAsync"
] and
mc.getTarget()
.getDeclaringType()
.hasQualifiedName("Microsoft.EntityFrameworkCore",
["RelationalDatabaseFacadeExtensions", "RelationalQueryableExtensions"]) and
this.getExpr() = mc.getAnArgument()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace Test
{
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

public class EfCoreInterpolatedTest : Controller
{
private DbContext _context;

// GOOD: ExecuteSqlInterpolated properly parameterizes interpolated strings
public void SafeExecuteInterpolated(string userInput)
{
_context.Database.ExecuteSqlInterpolated($"DELETE FROM Users WHERE Name = {userInput}");
}

// BAD: ExecuteSqlRaw with string concatenation is vulnerable
public void UnsafeExecuteRaw(string userInput)
{
_context.Database.ExecuteSqlRaw("DELETE FROM Users WHERE Name = '" + userInput + "'");
}
}
}

namespace Microsoft.EntityFrameworkCore
{
public class DbContext
{
public DatabaseFacade Database { get; }
}

public class DbSet<T> { }
}

namespace Microsoft.EntityFrameworkCore.Infrastructure
{
public class DatabaseFacade { }

public static class RelationalDatabaseFacadeExtensions
{
public static int ExecuteSqlInterpolated(this DatabaseFacade database, System.FormattableString sql) => 0;
public static int ExecuteSqlRaw(this DatabaseFacade database, string sql, params object[] parameters) => 0;
}

public static class RelationalQueryableExtensions
{
public static System.Linq.IQueryable<TEntity> FromSqlInterpolated<TEntity>(this DbSet<TEntity> source, System.FormattableString sql) where TEntity : class => null;
}
}
Loading