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 with this body:
{
"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"
}
]
}- 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.
- 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.
- 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.
The use case this job follows, with its automation and trigger: Produce a report or file, no repo.
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.