Skip to main content

A01 — Broken Access Control

OWASP ranks Broken Access Control as the #1 web application security risk. These rules detect missing authorization checks and misconfigurations that allow unauthenticated or unauthorized users to access protected resources.

OWASPA01001 — Missing authorization on controller action

PropertyValue
SeverityWarning
CategoryA01 Broken Access Control

What it detects

Controller actions in ASP.NET Core that lack both [Authorize] and [AllowAnonymous] attributes, where the controller itself also has no [Authorize] attribute.

Why it matters

Without explicit authorization, an action is implicitly public. Forgetting [Authorize] on a single action can expose sensitive data or operations to unauthenticated users.

❌ Non-compliant

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetProfile(int id) // no authorization!
{
return Ok(GetUser(id));
}
}

✅ Compliant

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
[HttpGet("{id}")]
[Authorize]
public IActionResult GetProfile(int id)
{
return Ok(GetUser(id));
}

[HttpGet("public")]
[AllowAnonymous]
public IActionResult PublicInfo() => Ok("public");
}

How to fix

Add [Authorize] to the action (or to the controller class to cover all actions), or add [AllowAnonymous] if public access is intentional.


OWASPA01002 — Hardcoded role string

PropertyValue
SeverityWarning
CategoryA01 Broken Access Control

What it detects

Hardcoded string literals passed to [Authorize(Roles = "...")] or User.IsInRole("...").

Why it matters

Hardcoded role strings create maintenance burden and are prone to typos that silently break authorization checks.

❌ Non-compliant

[Authorize(Roles = "Admin")]
public IActionResult DeleteUser(int id) { ... }

✅ Compliant

public static class Roles
{
public const string Admin = "Admin";
}

[Authorize(Roles = Roles.Admin)]
public IActionResult DeleteUser(int id) { ... }

OWASPA01003 — IsInRole with hardcoded string

PropertyValue
SeverityWarning
CategoryA01 Broken Access Control

What it detects

Calls to User.IsInRole("literal") with a hardcoded string argument.

❌ Non-compliant

if (User.IsInRole("Admin"))
{
// ...
}

✅ Compliant

if (User.IsInRole(Roles.Admin))
{
// ...
}

OWASPA01004 — CORS wildcard origin

PropertyValue
SeverityWarning
CategoryA01 Broken Access Control

What it detects

CORS policy configured with AllowAnyOrigin(), which sets the Access-Control-Allow-Origin: * header and allows any website to make cross-origin requests to your API.

Why it matters

A wildcard CORS policy allows malicious websites to make authenticated cross-origin requests on behalf of users, enabling CSRF-style attacks against APIs that rely on cookies or other ambient credentials.

❌ Non-compliant

builder.Services.AddCors(options =>
{
options.AddPolicy("MyPolicy", policy =>
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});

✅ Compliant

builder.Services.AddCors(options =>
{
options.AddPolicy("MyPolicy", policy =>
policy.WithOrigins("https://myapp.example.com")
.AllowAnyMethod()
.AllowAnyHeader());
});

OWASPA01005 — Missing antiforgery token

PropertyValue
SeverityWarning
CategoryA01 Broken Access Control

What it detects

HTTP POST/PUT/PATCH/DELETE controller actions in ASP.NET Core MVC that are not protected with [ValidateAntiForgeryToken] or [AutoValidateAntiforgeryToken] at the controller or action level.

Why it matters

Without antiforgery token validation, your endpoints are vulnerable to Cross-Site Request Forgery (CSRF) attacks where a malicious site can trigger state-changing requests on behalf of authenticated users.

❌ Non-compliant

[HttpPost]
public IActionResult CreateOrder(OrderDto dto) // CSRF-vulnerable
{
_orders.Add(dto);
return Ok();
}

✅ Compliant

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult CreateOrder(OrderDto dto)
{
_orders.Add(dto);
return Ok();
}

Or apply globally at the controller level:

[AutoValidateAntiforgeryToken]
public class OrderController : Controller { ... }

OWASPA01006 — SSRF via HttpClient

PropertyValue
SeverityError
CategoryA01 Broken Access Control
TechniqueTaint analysis

What it detects

User-controlled data (from query strings, route values, request body, or headers) flowing into HttpClient.GetAsync(), HttpClient.PostAsync(), HttpClient.SendAsync(), or similar HttpClient methods as the URL argument.

Why it matters

An attacker can set the URL to http://169.254.169.254/latest/meta-data/ (AWS instance metadata) or internal services like http://internal-db:5432/, gaining access to cloud credentials and internal infrastructure that should be gated behind access control.

❌ Non-compliant

[HttpGet]
public async Task<IActionResult> Proxy(string url)
{
// ❌ OWASPA01006: user-controlled URL passed to HttpClient
var response = await _httpClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
return Content(content);
}

✅ Compliant

[HttpGet]
public async Task<IActionResult> Proxy(string resourceId)
{
// Validate against an allowlist — never use user input as a full URL
if (!_allowedResources.TryGetValue(resourceId, out var safeUrl))
return BadRequest("Unknown resource");

var response = await _httpClient.GetAsync(safeUrl);
var content = await response.Content.ReadAsStringAsync();
return Content(content);
}

OWASPA01007 — SSRF via WebClient

PropertyValue
SeverityError
CategoryA01 Broken Access Control
TechniqueTaint analysis

What it detects

User-controlled data flowing into WebClient.DownloadString(), WebClient.DownloadData(), WebClient.UploadString(), or the WebClient.BaseAddress property.

❌ Non-compliant

[HttpPost]
public IActionResult Fetch(string url)
{
// ❌ OWASPA01007: SSRF via WebClient
using var client = new WebClient();
var data = client.DownloadString(url);
return Content(data);
}

✅ Compliant

Use HttpClient with a validated allowlist URL (see OWASPA01006 example). Avoid WebClient — it is a legacy API superseded by HttpClient.


OWASPA01008 — AllowAutoRedirect without validation

PropertyValue
SeverityWarning
CategoryA01 Broken Access Control

What it detects

HttpClientHandler configured with AllowAutoRedirect = true (the default) in a context where the initial URL is user-controlled — allowing an attacker to redirect the server to an internal endpoint via an open redirect.

Why it matters

Even if the initial URL is validated, a redirect response can point the client to an internal resource. With AllowAutoRedirect = true, the HttpClient will follow that redirect without re-validation.

❌ Non-compliant

var handler = new HttpClientHandler
{
AllowAutoRedirect = true // follows redirects, including to internal hosts
};
var client = new HttpClient(handler);
// then used with user-controlled URL

✅ Compliant

var handler = new HttpClientHandler
{
AllowAutoRedirect = false // validate redirect targets manually
};
var client = new HttpClient(handler);

If you need to follow redirects, validate each redirect target against your allowlist before following.