# Run a Security Audit on an ASP.NET Core App

Yes. An agent reads your ASP.NET Core pipeline, identity setup, CORS, endpoints and configuration, scans the packages, and reports each finding with a fix.

[Run this on Rush](https://cloud.getrush.ai/run/security-audit/aspnet-core/), in a Project that has your repository.

## What the agent does

The agent starts with the request pipeline, because that is where most ASP.NET Core findings live. In a solution like `jasontaylordev/CleanArchitecture`, `global.json` pins the .NET 10 SDK and `Directory.Build.props` turns on `TreatWarningsAsErrors` and nullable reference types for every project. `src/Web/Program.cs` calls `AddServiceDefaults`, `AddKeyVaultIfConfigured`, `AddApplicationServices`, `AddInfrastructureServices` and `AddWebServices`, then `UseHsts` outside development, `UseHttpsRedirection`, and `UseCors` with a policy built inline from `AllowAnyMethod()`, `AllowAnyHeader()` and `AllowAnyOrigin()`. It maps OpenAPI and the Scalar reference UI in every environment, registers the `ProblemDetailsExceptionHandler`, and `MapDefaultEndpoints` in `src/ServiceDefaults/Extensions.cs` exposes `/health` and `/alive` only when the environment is Development. The agent reads each of those lines as a decision and asks whether it was meant.

Then it reads who can do what. `src/Web/Infrastructure/WebApplicationExtensions.cs` discovers every `IEndpointGroup` and maps it under `/api/{ClassName}`; `TodoItems`, `TodoLists` and `WeatherForecasts` call `RequireAuthorization()` on their group, and `Users` calls `MapIdentityApi<ApplicationUser>()`, which publishes register, login, refresh, password reset and two-factor endpoints to anyone, plus a `logout` endpoint that requires authorization and a non-null body. `src/Infrastructure/DependencyInjection.cs` configures `AddIdentityCore` with roles and either bearer tokens or identity cookies depending on the template option, and the agent checks the password, lockout and confirmed-account options that are left at their defaults. The MediatR pipeline in `src/Application/Common/Behaviours/AuthorizationBehaviour.cs` enforces `[Authorize]` attributes with roles and policies on requests, and the agent lists which commands and queries carry one, `GetTodos` among them, and which rely on the endpoint group alone.

Configuration and secrets come next. `src/Web/appsettings.json` sets `AllowedHosts` to `*` and a SQLite connection string, `AddKeyVaultIfConfigured` reads `AZURE_KEY_VAULT_ENDPOINT` and uses `DefaultAzureCredential`, and `src/Web/Web.http` ships an administrator email and password for local requests, so the agent checks `ApplicationDbContextInitialiser` to see whether those credentials are seeded in every environment or only in development. It looks for rate limiting on the identity endpoints and finds none, for security headers beyond HSTS and finds none, and reads the `ProblemDetailsExceptionHandler` to confirm that unhandled exceptions do not leak stack traces outside development, where `AddDatabaseDeveloperPageExceptionFilter` is registered.

Finally it checks the packages. `Directory.Packages.props` manages every version centrally, so the agent runs `dotnet list package --vulnerable --include-transitive` and `dotnet list package --outdated` across the solution and reads `renovate.json` and `.github/workflows/codeql.yml` to say what the repository already scans. The result is `security-audit.md`, ordered by severity, each finding with the file and line, what it allows, and a fix written for this solution: a named CORS policy with an origin list from configuration, `AddRateLimiter` on the identity group, `AllowedHosts` set to the real hostnames, Scalar behind an environment check, and the identity options to tighten. The agent changes no code and opens no pull request.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Run a security audit on this ASP.NET Core solution without changing anything. Read global.json, Directory.Build.props, Directory.Packages.props, src/Web/Program.cs, src/Web/DependencyInjection.cs, every file under src/Web/Endpoints and src/Web/Infrastructure, src/Web/appsettings.json and the other appsettings files, src/Web/Web.http, src/Infrastructure/DependencyInjection.cs, src/Infrastructure/Identity, src/Infrastructure/Data/ApplicationDbContextInitialiser.cs, src/Application/Common/Behaviours/AuthorizationBehaviour.cs, src/ServiceDefaults/Extensions.cs, renovate.json and the workflows under .github/workflows first. For the pipeline, report the CORS policy, HSTS and HTTPS redirection, which environments expose OpenAPI, Scalar and the health endpoints, and what the exception handler returns. For identity, list every endpoint MapIdentityApi publishes and which endpoint groups and MediatR requests require authorization, and report the password, lockout, confirmed-account and token lifetime options in effect. Report AllowedHosts, how secrets are read, whether the administrator credentials in Web.http are seeded outside development, and whether any rate limiting or security headers exist. Run dotnet list package --vulnerable --include-transitive and dotnet list package --outdated and quote the output. Write security-audit.md: findings ordered by severity, each with file and line, impact, and a fix written for this solution, then a dependency section, then what the solution already does right. Change no code and open no pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is `security-audit.md` as an artifact on the session, with a download link the session read returns. The findings come first, ordered by severity, each with the file and line, a sentence on what it allows and for whom, and the fix as it would be written in this solution: the named CORS policy and the configuration key it reads, the `AddRateLimiter` registration and the group it attaches to, the environment check around `MapScalarApiReference`.

A dependency section quotes `dotnet list package --vulnerable --include-transitive` and `--outdated`, with the advisory for each flagged package and the version in `Directory.Packages.props` that resolves it, and notes what Renovate and CodeQL already cover. A closing section lists what the solution does right: `TreatWarningsAsErrors` and nullable on every project, `UseHsts` and `UseHttpsRedirection`, health endpoints hidden outside development, ProblemDetails responses that carry no stack trace, and authorization enforced in the MediatR pipeline as well as at the endpoint.

A reviewer decides which findings apply to how the app is deployed, since a wide-open CORS policy matters differently behind a gateway than on the public internet, and sends a follow-up message to the same session asking the agent to apply the chosen fixes and open a pull request, with `dotnet build` and `dotnet test` run in the sandbox that already has the solution restored.

## Run it on every release candidate branch

A team that cuts a release branch before each deploy starts one run per release with `POST /o/{org}/sessions`, that branch in `resources` as `https://github.com/your-org/your-app/tree/release-2.3`, and this prompt. A step in the release workflow sends the request with the key from its secrets and attaches the artifact link to the release.

A webhook on the key receives `run.completed` with the `session_url`, so the workflow can wait for the report and hold the release if a finding above an agreed severity appears in the artifact.

## Why run it on Rush?

A security review of an ASP.NET Core solution means reading the pipeline in `Program.cs`, the identity options behind `AddIdentityCore`, every endpoint group's authorization and every `appsettings` file, then running the package scan. Done by hand it is a day that slips to next sprint. In a Rush sandbox the agent reads all of it, restores the solution, runs `dotnet list package`, and keeps every command and its output in the transcript, so each finding points at a line and each dependency claim at an advisory.

The report separates what is a template default from what is a risk in production, and says which fixes are one line, such as a named CORS policy, and which need a decision, such as whether open registration through `MapIdentityApi` is wanted at all. The same prompt runs against every ASP.NET Core service the team owns.

## Frequently asked questions

### Does it change any code or open a pull request?

No. The result is a report with a fix for each finding written for this solution. A follow-up message to the same session asks the agent to apply the ones you choose, run `dotnet build` and `dotnet test`, and open a pull request.

### Why is a CORS policy with AllowAnyOrigin a finding when the API uses cookies?

Because the report rates it by what it allows in each mode the solution supports. With identity cookies, the browser will not send credentials to an any-origin policy, so the exposure is anonymous endpoints; with bearer tokens in the API-only mode, any page that holds a token can call the API from any origin. Either way a named policy with configured origins costs a few lines and removes the question.

### Does it flag the administrator credentials in Web.http?

It reads `ApplicationDbContextInitialiser` to see where they are seeded. If the seed runs only in development, the finding is informational and says so; if it can run in production, it is a high-severity finding with the change that stops it.

### What does the package scan cover?

Everything `Directory.Packages.props` manages, including transitive packages, through `dotnet list package --vulnerable --include-transitive`, plus `--outdated` for the versions behind. The report quotes the output and notes that `renovate.json` and CodeQL already run, so the team can see what the scan adds.

### Will it understand the template's conditional code?

Yes. Files like `Program.cs` and `Infrastructure/DependencyInjection.cs` carry `#if (UseApiOnly)` and `#if (UsePostgreSQL)` blocks, and the report says which branch applies to the app as built and audits that one, while noting where the other branch would change a finding.
