Skip to content

VNX-CS-005: C# MVC action accepting cross-site form posts without anti-forgery validation

Detects ASP.NET MVC and ASP.NET Core MVC controller actions reachable by a cross-site form ([HttpPost], [AcceptVerbs(HttpVerbs.Post)], and PUT/DELETE/PATCH where method override applies) with no anti-forgery validation on the action, the controller, a base controller or a global filter.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-CS-005
Severity Medium
SARIF level warning
Kind sast
Languages C#
CWE CWE-352
CAPEC CAPEC-62
ATT&CK T1185
CWSS vector CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags csrf mvc csharp
Source internal/sast/rules/vnx-cs-005.rego

Overview

This rule reports the [HttpPost] (or [AcceptVerbs(HttpVerbs.Post)]) attribute of an action in a class deriving from Controller when neither the action’s own attribute block nor the controller carries [ValidateAntiForgeryToken], [AutoValidateAntiforgeryToken] or [IgnoreAntiforgeryToken]. [HttpPut], [HttpDelete] and [HttpPatch] are reported only where a cross-site form can reach them: in ASP.NET MVC 5, which honours X-HTTP-Method-Override, or in a project that calls UseHttpMethodOverride. A global AutoValidateAntiforgeryTokenAttribute filter, a base controller carrying the attribute, [ApiController], ControllerBase and Web API 2 ApiController classes, actions limited to JSON by [Consumes("application/json")] or a [FromBody] parameter, and test code are not reported. A comment such as // TODO: add [ValidateAntiForgeryToken] does not count as the mitigation.

Cross-Site Request Forgery (CSRF) exploits the fact that browsers automatically attach cookies, including session cookies, to all requests sent to a domain, regardless of which site triggered the request. A malicious page on a different origin can silently submit forms or fire AJAX requests to a victim’s authenticated session on a target site, causing state changes the user did not intend.

The [ValidateAntiForgeryToken] attribute stops CSRF by requiring the request to include a value that was generated by the server, embedded in the HTML page, and known only to the legitimate client. A cross-origin attacker cannot read the token from the victim’s browser because the Same-Origin Policy blocks cross-origin reads.

Why This Matters

CSRF attacks are invisible to the victim. An attacker embeds a hidden form or an <img> tag with a carefully crafted src attribute in a page the victim visits, social media, email HTML, or an ad banner are all valid vectors. When the victim’s browser loads that page while logged into the target site, the attack executes silently: a fund transfer is initiated, an email address is changed, a password reset is triggered, or an admin account is created.

Banking applications, e-commerce sites, and SaaS admin panels are the most common targets. CSRF vulnerabilities in administrative actions are particularly severe: an attacker who tricks a site administrator into visiting a malicious link can create new admin users, change billing details, delete content, or take over the entire application, all without ever obtaining the admin’s password or cookie value.

Modern SPAs that use Authorization: Bearer headers with JWT tokens are not vulnerable to CSRF because browsers do not automatically attach custom headers. However, classic MVC applications that rely on cookie-based session authentication, the default in ASP.NET MVC, require CSRF protection on every state-changing endpoint.

What Gets Flagged

// FLAGGED: [HttpPost] action without [ValidateAntiForgeryToken]
[HttpPost]
public ActionResult TransferFunds(TransferViewModel model)
{
    _bankService.Transfer(model.FromAccount, model.ToAccount, model.Amount);
    return RedirectToAction("Index");
}

// FLAGGED in ASP.NET MVC 5 (or with UseHttpMethodOverride): [HttpDelete] without token validation
[HttpDelete]
public IActionResult DeleteUser(int id)
{
    _userService.Delete(id);
    return NoContent();
}

Remediation

  1. Add [ValidateAntiForgeryToken] to every individual state-changing action, or apply [AutoValidateAntiforgeryToken] to the entire controller class (preferred, prevents accidentally missing new actions).
  2. In the corresponding Razor views, include @Html.AntiForgeryToken() inside every <form> tag, or use the asp-antiforgery="true" tag helper which renders the token automatically.
  3. For Razor Pages, CSRF protection is enabled by default, do not disable it.
  4. For API controllers that use bearer tokens instead of cookies, exclude them explicitly with [IgnoreAntiforgeryToken] or move them to a separate controller that does not use cookie authentication.
  5. Configure AutoValidateAntiforgeryTokenAttribute as a global filter in Startup.cs / Program.cs so all controllers are protected by default.
// SAFE: AutoValidateAntiforgeryToken at controller level covers all actions
[AutoValidateAntiforgeryToken]
public class AccountController : Controller
{
    [HttpPost]
    public ActionResult TransferFunds(TransferViewModel model)
    {
        _bankService.Transfer(model.FromAccount, model.ToAccount, model.Amount);
        return RedirectToAction("Index");
    }
}

// SAFE: token explicitly validated on individual action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DeleteUser(int id)
{
    _userService.Delete(id);
    return RedirectToAction("Users");
}

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-cs-005
// nosec vnx-cs-005

Or record an ignore rule: vulnetix ignore add --rule vnx-cs-005 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-cs-005.rego, cli/internal/sast/docs/vnx-cs-005.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.