csharp.dotnet.security.mvc-missing-antiforgery.mvc-missing-antiforgery
semgrep
Author
unknown
Download Count*
License
$METHOD is a state-changing MVC method that does not validate the antiforgery token or do strict content-type checking. State-changing controller methods should either enforce antiforgery tokens or do strict content-type checking to prevent simple HTTP request types from bypassing CORS preflight controls.
Run Locally
Run in CI
Defintion
rules:
- id: mvc-missing-antiforgery
message: $METHOD is a state-changing MVC method that does not validate the
antiforgery token or do strict content-type checking. State-changing
controller methods should either enforce antiforgery tokens or do strict
content-type checking to prevent simple HTTP request types from bypassing
CORS preflight controls.
severity: WARNING
metadata:
likelihood: LOW
impact: MEDIUM
confidence: LOW
category: security
cwe:
- "CWE-352: Cross-Site Request Forgery (CSRF)"
cwe2021-top25: true
cwe2022-top25: true
owasp:
- A01:2021 - Broken Access Control
references:
- https://cheatsheetseries.owasp.org/cheatsheets/DotNet_Security_Cheat_Sheet.html#cross-site-request-forgery
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
subcategory:
- audit
technology:
- .net
- mvc
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
vulnerability_class:
- Cross-Site Request Forgery (CSRF)
languages:
- csharp
patterns:
- pattern: |
[$HTTPMETHOD]
public IActionResult $METHOD(...){
...
}
- pattern-inside: |
using Microsoft.AspNetCore.Mvc;
...
- pattern-not: |
[ValidateAntiForgeryToken]
public IActionResult $METHOD(...){
...
}
- pattern-not: |
[Consumes(...)]
public IActionResult $METHOD(...){
...
}
- metavariable-regex:
metavariable: $HTTPMETHOD
regex: Http(Post|Put|Delete|Patch)
Examples
mvc-missing-antiforgery.cs
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using MvcMovie.Models;
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
//ruleid: mvc-missing-antiforgery
[HttpPost]
public IActionResult CreateBad(User user){
CreateUser(user);
}
//ruleid: mvc-missing-antiforgery
[HttpDelete]
public IActionResult DeleteBad(User user){
DeleteUser(user);
}
//ok: mvc-missing-antiforgery
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult CreateGood(User user){
CreateUser(user);
}
//ok: mvc-missing-antiforgery
[HttpPost]
//strict type checking enforces CORS preflight for non-simple HTTP requests
[Consumes("application/json")]
public IActionResult CreateGood(User user){
CreateUser(user);
}
//ok: mvc-missing-antiforgery
[ValidateAntiForgeryToken]
[HttpDelete]
public IActionResult DeleteGood(User user){
CreateUser(user);
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
Short Link: https://sg.run/Y0Jy