Secure C#/.NET Development
These rules apply to all C#/.NET code in the repository and aim to prevent common security risks through disciplined use of input validation and deserialization, output encoding, and safe APIs.
These rules apply to all C#/.NET code in the repository and aim to prevent common security risks through disciplined use of input validation and deserialization, output encoding, and safe APIs.
--- description: globs: **/*.cs, **/*.sln, **/*.csproj alwaysApply: false ---
These rules apply to all C#/.NET code in the repository and aim to prevent common security risks through disciplined use of input validation and deserialization, output encoding, and safe APIs.
All violations must include a clear explanation of which rule was triggered and why, to help developers understand and fix the issue effectively. Generated code must not violate these rules. If a rule is violated, a comment must be added explaining the issue and suggesting a correction.
For file validation, utilize MIME Type Validation libraries, like `MimeDetective` or `HeyRed.Mime` to check whether a file's type and content actually matches the expected type.
// Vulnerable to SQL Injection
var user = dbContext.Users
.FromSqlRaw(quot;SELECT * FROM Users WHERE Username = '{userInput}'")
.FirstOrDefault(); //Input is interpolated and parameterized internally
var user = dbContext.Users
.FromSqlInterpolated(quot;SELECT * FROM Users WHERE Username = {userInput}")
.FirstOrDefault(); //LINQ is translated into parameterized SQL query
var user = dbContext.Users
.Where(u => u.Username == userInput)
.FirstOrDefault(); var builder = WebApplication.CreateBuilder(args);
// One instance is shared for all users - sensitive data is exposed to others
builder.Services.AddSingleton<UserAuthService>(); var builder = WebApplication.CreateBuilder(args);
// Each created instance is scoped for a single request
builder.Services.AddScoped<UserAuthService>(); var formatter = new BinaryFormatter(); // No validation of untrusted data
using var ms = new MemoryStream(data);
return formatter.Deserialize(ms); var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
return JsonSerializer.Deserialize<T>(json, options); // Type-safe string basePath = "/home/files/";
// Dangerous - filename can contain "../../etc/passwd"
string fullPath = Path.Combine(basePath, filename);
string content = System.IO.File.ReadAllText(fullPath); string basePath = "/home/files/";
// Absolute path is resolved and normalized
string fullPath = Path.GetFullPath(Path.Combine(basePath, filename));
// Ensure the resolved path starts with the base path
if (!fullPath.StartsWith(basePath, StringComparison.Ordinal))
{
return BadRequest("Invalid file path.");
}
if (!System.IO.File.Exists(fullPath))
{
return NotFound();
}
string content = System.IO.File.ReadAllText(fullPath);