Skip to main content

C# (.NET) · SAST

C# / .NET SAST that runs entirely offline

Audit ASP.NET Core, Entity Framework, Dapper and NHibernate for OWASP Top 10 vulnerabilities, deserialization gadgets, and configuration drift — without leaving your machine.

Frameworks & libraries scanned

We test fixture coverage on these frameworks. New patterns are added with each builtin rule release.

ASP.NET Core ASP.NET MVC Entity Framework Core Dapper NHibernate Razor Blazor SignalR IdentityServer NewtonsoftJson System.Text.Json BouncyCastle.NetCore Polly AutoMapper

Top CWE classes detected

These CWE classes appear most often in modern codebases of this language. StaticCodeAudit ships dedicated rules for each, mapped to OWASP Top 10 / ISO 27001 / ASVS where relevant.

CWE-89

SQL Injection

String concatenation in SqlCommand.CommandText, Dapper Execute($"..."), EF Core FromSqlRaw with interpolation, NHibernate HQL with concat.

Detected by SCA rule: sql_injection_concat_csharp

CWE-78

OS Command Injection

Process.Start(new ProcessStartInfo { FileName = "cmd", Arguments = userInput }) with shell parsing. UseShellExecute = true increases attack surface.

Detected by SCA rule: command_injection_csharp

CWE-502

Insecure Deserialization

BinaryFormatter.Deserialize (obsolete since .NET 5 but still found), NetDataContractSerializer, SoapFormatter on untrusted streams.

Detected by SCA rule: unsafe_deserialization

CWE-79

Cross-Site Scripting (XSS)

Razor @Html.Raw(model.Bio) with untrusted data, MVC HttpUtility.HtmlEncode bypassed, Blazor MarkupString on user input.

Detected by SCA rule: xss_raw_html

CWE-798

Hardcoded Credentials

Connection strings in appsettings.json committed, JWT signing key as const string, Azure secrets in web.config.

Detected by SCA rule: hardcoded_secret

CWE-352

CSRF

[ValidateAntiForgeryToken] missing on POST actions, options.SuppressXFrameOptionsHeader = true in Startup.

Detected by SCA rule: csrf_missing_aspnet

Vulnerable vs. clean — three quick examples

CWE-89 Detected by SCA rule: sql_injection_concat_csharp
❌ Vulnerable
// Vulnerable — SqlCommand concat
var cmd = new SqlCommand(
    $"SELECT * FROM users WHERE name = \'{name}\'", conn);
var reader = cmd.ExecuteReader();
✅ Clean / safe
// Clean — parameterized
var cmd = new SqlCommand(
    "SELECT * FROM users WHERE name = @name", conn);
cmd.Parameters.AddWithValue("@name", name);
var reader = cmd.ExecuteReader();
CWE-502 Detected by SCA rule: unsafe_deserialization
❌ Vulnerable
// Vulnerable — BinaryFormatter on untrusted stream
var bf = new BinaryFormatter();
var obj = bf.Deserialize(networkStream);
✅ Clean / safe
// Clean — System.Text.Json with known schema
var obj = JsonSerializer.Deserialize<UserDto>(
    networkStream,
    new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
CWE-79 Detected by SCA rule: xss_raw_html
❌ Vulnerable
// Vulnerable — Razor @Html.Raw on user data
@Html.Raw(Model.Bio)
✅ Clean / safe
// Clean — default-encoded output
@Model.Bio

What StaticCodeAudit detects (this language)

  • SQL injection in SqlCommand concat, Dapper interpolation, EF Core FromSqlRaw, NHibernate HQL concat
  • XSS in Razor @Html.Raw, Blazor MarkupString, MVC manual encoding bypass
  • Command injection in Process.Start with shell parsing
  • BinaryFormatter deserialization on untrusted streams (still appears despite .NET deprecation)
  • Hardcoded secrets in appsettings.json, web.config committed
  • CSRF: [ValidateAntiForgeryToken] missing on POST actions
  • Insecure cookies (CookieOptions.Secure, HttpOnly, SameSite off)
  • Path traversal in File.ReadAllBytes, Path.Combine with user paths
  • XXE in XmlDocument, XmlReaderSettings.DtdProcessing = Parse
  • Insecure crypto (MD5/SHA1 for security, ECB mode, hardcoded keys)
  • JWT none algorithm, hardcoded HS256 secret, no expiration claim
  • Open redirect via Redirect(Request.Query["url"])
  • Deprecated APIs (BinaryFormatter, NetDataContractSerializer, SHA1Managed)
  • CI/CD misconfigurations (.gitlab-ci, GitHub Actions, NuGet feed insecure)

Curious how detection quality is actually measured? See the full cross-language benchmark methodology (OWASP Benchmark, NIST Juliet, precision/recall/F1 per language) →

CVE Test Suite — the honest number for ASP.NET

StaticCodeAudit was measured against a real-world CVE Test Suite: 45 cases reconstructed from published, historical CVEs across 8 frameworks and 5 languages. ASP.NET is one of them — and it is the lowest-scoring framework in the whole suite.

66.7%
F1 Score
66.7%
Recall
45
CVE Test Suite (total, all languages)

ASP.NET, CVE-reconstructed

66.7%
ASP.NET (CVE-reconstructed)

Disclosed, not hidden: ASP.NET/C# sits lowest on the cross-language CVE table, both precision and recall in the 66.7% range. Historical CVEs like log4shell-style deserialization chains and complex multi-hop taint paths in ASP.NET are the specific cases the rule engine still misses. Full cross-language breakdown (including where Python and PHP score higher) on the <a href="/language-benchmarks.php" class="text-primary font-semibold hover:underline">language benchmarks page</a>.

Real vulnerabilities rarely live in one file

ASP.NET applications split logic across layers: a controller receives the request, a repository builds the query. A scanner limited to one file at a time never connects the two — it sees user input in OrdersController.cs and a database call in OrderRepository.cs, but never the link between them. StaticCodeAudit follows the data across files.

OrdersController.cs
[HttpGet("orders/{id}")]
public IActionResult GetOrder(string id)
{
    return Ok(_repo.FindOrder(id));
}
OrderRepository.cs
public Order FindOrder(string id)
{
    var sql = $"SELECT * FROM Orders WHERE Id = \'{id}\'";
    return _connection.QueryFirst<Order>(sql);
}

id comes from the route parameter in the controller, and reaches the SQL query one file later, unmodified — StaticCodeAudit reports it at the exact line where the query runs.

How does this compare to Security Code Scan or Semgrep?

Security Code Scan and Semgrep are the two tools that come up first when a .NET team looks for a free security scanner. Both are legitimate, and many teams already run one of them — here's an honest comparison, not a takedown.

Security Code Scan

Free, open-source

Roslyn analyzer built specifically for .NET security issues (SQL injection, XSS, XXE, weak crypto), runs inside the compiler as you build. Good default coverage, but single-project analysis: no cross-file taint tracking across a multi-project solution, and findings aren't mapped to CWE/ISO 27001/ASVS out of the box.

Semgrep (Community)

Free, open-source core

Pattern-matching engine covering many languages, with C# support newer and less mature than its Python/Java/JS coverage. The free tier covers most day-to-day rules; cross-file taint tracking, compliance reporting and some enterprise integrations sit behind Semgrep's paid tiers.

Full StaticCodeAudit vs Semgrep comparison →

Neither of these gets replaced by installing StaticCodeAudit — if Security Code Scan already flags what your team needs, keep running it. What StaticCodeAudit adds on top: findings pre-mapped to CWE/OWASP/ISO 27001/ASVS/NIST CSF (a finding that's audit-ready, not just a rule ID), cross-file taint tracking across your whole solution by default, and 7 other languages covered by the same binary — no separate scanner to configure per language. Many teams run both.

Audit your codebase

Audit ASP.NET Core, Entity Framework, Dapper and NHibernate for OWASP Top 10 vulnerabilities, deserialization gadgets, and configuration drift — without leaving your machine.

Download demo binary Book a walkthrough