.NET
AI agent detection for ASP.NET Core and .NET Framework
Checkpoint for .NET works on ASP.NET Core (6, 7, 8, 9) and .NET Framework (4.6.2 through 4.8.1). One package, pick your runtime, ship.
Install
dotnet add package KyaOs.CheckpointInstall-Package KyaOs.CheckpointNuGet resolves the right adapter for your project's target framework automatically.
Quick start
Register in Program.cs:
using Checkpoint.AspNetCore.Extensions;
using Checkpoint.Core.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCheckpoint(options =>
{
options.ProjectId = builder.Configuration["Checkpoint:ProjectId"]!;
options.ApiKey = builder.Configuration["Checkpoint:ApiKey"]!;
options.OnAgentDetected = DetectedAction.Block;
});
var app = builder.Build();
app.UseCheckpoint(); // before routing + auth
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();Set credentials in appsettings.json:
{
"Checkpoint": {
"ProjectId": "your_project_id",
"ApiKey": "your_api_key"
}
}On .NET Framework, Checkpoint is a classic IHttpModule — the same registration works for MVC 5, Web API 2, and Web Forms.
Requires a 64-bit host process. Azure App Service B1 or higher with Platform = 64-bit in Configuration → General Settings, or Windows Server IIS with Enable 32-Bit Applications = False in the app pool's Advanced Settings. Azure App Service Free (F1) and Shared (D1) tiers are 32-bit only and not supported — the site will refuse to start at module init with a clear error if the host is 32-bit.
No code changes. Add to Web.config:
<configuration>
<appSettings>
<add key="Checkpoint:ProjectId" value="your_project_id" />
<add key="Checkpoint:ApiKey" value="your_api_key" />
<add key="Checkpoint:OnAgentDetected" value="Block" />
</appSettings>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="Checkpoint"
type="Checkpoint.AspNet.CheckpointModule, Checkpoint.AspNet" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
</configuration>runAllManagedModulesForAllRequests="true" is required so detection runs on static files too.
Deploy. Checkpoint runs on every request.
Configuration
builder.Services.AddCheckpoint(options =>
{
options.ProjectId = "your_project_id";
options.ApiKey = "your_api_key";
options.OnAgentDetected = DetectedAction.Block;
options.ConfidenceThreshold = 70;
options.SkipPaths = ["/health", "/api/webhooks/*"];
options.IncludePaths = ["/api/*"];
options.McpServerUrl = "https://mcp.example.com";
options.SiteName = "My Website";
options.BlockedResponse = new BlockedResponseOptions
{
StatusCode = 403,
Message = "Access denied: AI agent detected",
};
});<appSettings>
<add key="Checkpoint:ProjectId" value="your_project_id" />
<add key="Checkpoint:ApiKey" value="your_api_key" />
<add key="Checkpoint:OnAgentDetected" value="Block" />
<add key="Checkpoint:ConfidenceThreshold" value="70" />
<add key="Checkpoint:SkipPaths" value="/health,/api/webhooks/*" />
<add key="Checkpoint:IncludePaths" value="/api/*" />
<add key="Checkpoint:McpServerUrl" value="https://mcp.example.com" />
<add key="Checkpoint:SiteName" value="My Website" />
</appSettings>Web.config uses the same key names as appsettings.json. Comma-separated values for list options like SkipPaths and IncludePaths.
Detection actions
| Action | Behavior |
|---|---|
Allow | Let the request through silently |
Log | Log and allow |
Block | Return 403 |
Redirect | 302 to McpServerUrl |
Instruct | 401 with KYA-OS authorization instructions for the agent |
Path filtering
IncludePaths takes priority — if set, only matching paths are processed. Both support wildcard suffixes (/api/*).
Access detection results
Detection results live on HttpContext.Items — read them in controllers or downstream middleware.
public IActionResult Get()
{
var result = HttpContext.Items["Checkpoint.Result"] as DetectionResult;
if (result?.IsAgent == true)
{
return Ok(new { agent = result.DetectedAgent?.Name, confidence = result.Confidence });
}
return Ok(new { message = "Hello human!" });
}public IHttpActionResult Get()
{
var result = HttpContext.Current.Items["Checkpoint.Result"] as DetectionResult;
if (result?.IsAgent == true)
{
return Ok(new { agent = result.DetectedAgent?.Name, confidence = result.Confidence });
}
return Ok(new { message = "Hello human!" });
}Response headers
Every response includes detection metadata:
| Header | Value | When |
|---|---|---|
KYA-Detected | true / false | Always |
KYA-Confidence | 0–100 | Always |
KYA-Class | Human / AiAgent / Bot | Always |
KYA-Agent | Agent name | When detected |
KYA-Verification | Pattern / Signature | When detected |
Signature verification
Ed25519 signature verification for ChatGPT (RFC 9421) and KYA Agent DID is on by default. Verified agents get 100% confidence. ChatGPT's public key refreshes automatically from OpenAI's JWKS.
To disable:
options.EnableSignatureVerification = false;<add key="Checkpoint:EnableSignatureVerification" value="false" />KYA-OS instruct mode
DetectedAction.Instruct returns a 401 with KYA-OS authentication instructions — WWW-Authenticate: KYA header, a machine-readable mcp_i JSON body, and a plain-language message the agent can relay to its user.
options.OnAgentDetected = DetectedAction.Instruct;
options.McpServerUrl = "https://mcp.example.com";<add key="Checkpoint:OnAgentDetected" value="Instruct" />
<add key="Checkpoint:McpServerUrl" value="https://mcp.example.com" />Dashboard reporting
Detection events flow to your Checkpoint dashboard automatically — every AI agent and bot classified above the confidence threshold is reported fire-and-forget after the request completes. Pure human traffic is not reported. Same payload, same gating, and same dashboard experience across ASP.NET Core and .NET Framework.
Requires Checkpoint:ProjectId and Checkpoint:ApiKey to be set. Without them, detection and enforcement still run — only the dashboard hop is skipped.
Upgrading
Already running Checkpoint and want to move to the latest release? The path
is the same across runtimes: bump the package version, restore, redeploy.
No source changes for any release on the 1.x line.
The current stable release is 1.0.1.
# If you installed the metapackage (recommended)
dotnet add package KyaOs.Checkpoint --version 1.0.1
# If you installed the adapter package directly
dotnet add package Checkpoint.AspNetCore --version 1.0.1dotnet add package KyaOs.Checkpoint --version 1.0.1In Visual Studio's Package Manager Console:
Update-Package KyaOs.Checkpoint -Version 1.0.1NuGet will rewrite packages.config, refresh the binding-redirect XDT in
Web.config, and refresh the wasmtime.dll copy in bin/ automatically.
After the bump: dotnet restore, rebuild, redeploy. No code changes.
Should I switch to the metapackage?
If your csproj references Checkpoint.AspNetCore or Checkpoint.AspNet
directly, both packages remain first-class and continue to ship at the same
version cadence — you do not have to switch. Switching to KyaOs.Checkpoint
is purely a discoverability and forward-compatibility convenience:
- One install command works for any target framework (NuGet picks the adapter for you).
- New runtimes added to the metapackage in the future are picked up automatically.
- Namespaces and API are identical —
using Checkpoint.AspNetCore.Extensions;andAddCheckpoint(...)continue to compile unchanged.
To switch, swap the package reference and rebuild — no source edits.
Breaking change to know about: response headers renamed in 0.4.0
If you are upgrading from 0.3.x or earlier to 0.4.0 or later (which
includes any move to a 1.x release), the custom response headers were
renamed per RFC 6648 (deprecating the X- prefix) and the KYA-OS rebrand.
The middleware behavior is identical — only the header names changed.
| Pre-0.4.0 header | 0.4.0+ header |
|---|---|
X-Checkpoint-Detected | KYA-Detected |
X-Checkpoint-Confidence | KYA-Confidence |
X-Checkpoint-Class | KYA-Class |
X-Checkpoint-Agent | KYA-Agent |
X-Checkpoint-Verification | KYA-Verification |
X-Checkpoint-Session | KYA-Session |
X-KYA-OS-Required | KYA-Auth-Required |
X-KYA-OS-Authorize | KYA-Auth-Url |
X-KYA-OS-Project | KYA-Project |
X-AgentShield-Action | KYA-Action |
If you have downstream code, log queries, alerts, WAF rules, or monitoring
dashboards keyed off the old names, search-and-replace before deploying.
There are no other breaking changes on the path from 0.3.x to 1.0.1.
Verifying the upgrade
After the redeploy, three quick checks:
# 1. Confirm the new header set is present
curl -sI https://your-site.example.com/ -A "GPTBot/1.0" \
| grep -i "^KYA-"
# Expect KYA-Detected, KYA-Confidence, KYA-Class, KYA-Agent at minimum.# 2. Confirm classification is correct (a known bot should report bot, not ai_agent)
curl -sI https://your-site.example.com/ -A "Googlebot/2.1 (+http://www.google.com/bot.html)" \
| grep -i "^KYA-Class"
# Expect: KYA-Class: Bot# 3. Confirm dashboard rows show the correct detection class
# In your Checkpoint dashboard, filter the Detections table by
# source=middleware and detectionClass=bot. The Googlebot probe from
# step 2 should appear there within ~30 seconds. Pre-0.3.2 sites
# emitted these as detectionClass=ai_agent instead.If KYA-_ headers are absent but X-Checkpoint-_ are still present, the new
package did not load — check that dotnet restore ran and that the build
output's Checkpoint.Core.dll reports the new version
(AssemblyInformationalVersion matches 1.0.1).
If KYA-Class reports AiAgent for known crawlers like Googlebot, the
embedded engine is stale — confirm Checkpoint.Core resolved to 1.0.1
in obj/project.assets.json. The dependabot lockstep groups in the
demo repo can be used as a reference for keeping Checkpoint.* packages
on a single version.
Troubleshooting
The errors below are specific to the .NET Framework adapter. Modern ASP.NET Core installs don't hit any of them.
Module fails to start with PlatformNotSupportedException
Symptom. First request returns a 500, with an exception whose message begins:
Checkpoint requires a 64-bit host process. Current process is 32-bit.Cause. The app pool is running in 32-bit mode. Checkpoint's WebAssembly runtime ships x64 only and has no 32-bit fallback.
Fix.
- Azure App Service. Upgrade the App Service Plan from Free (F1) or Shared (D1) to Basic (B1) or higher. In the portal, open Configuration → General Settings, set Platform to 64-bit, and restart the app.
- IIS on Windows Server. In IIS Manager, open Application Pools → your pool → Advanced Settings and set Enable 32-Bit Applications to
False. - Standalone host. Add
<PlatformTarget>x64</PlatformTarget>to your csproj, orAnyCPUwith<Prefer32Bit>false</Prefer32Bit>.
FileLoadException with HRESULT 0x80131040
Symptom. First request returns a 500, with an error like:
Could not load file or assembly 'Microsoft.Extensions.Logging.Abstractions'
or one of its dependencies. (0x80131040)Cause. Classic ASP.NET needs binding redirects in Web.config for the transitive Microsoft.Extensions.* and System.Text.Json dependency graph. Checkpoint.AspNet 0.2.1+ ships an auto-generated redirect set inside the NuGet package, but it's applied differently depending on whether your project uses packages.config or PackageReference.
Fix for packages.config. No action needed. NuGet applies the transform to Web.config automatically on Install-Package.
Fix for PackageReference. NuGet does not auto-transform content files for PackageReference projects. Pick one:
-
Enable MSBuild auto-redirect generation in your consumer csproj (recommended):
<PropertyGroup> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> </PropertyGroup> -
Copy the shipped redirect set manually. Open the XDT at the path below, copy its
<runtime>block, and paste it into yourWeb.config:~/.nuget/packages/checkpoint.aspnet/<version>/contentFiles/any/net462/web.config.install.xdt
FileNotFoundException for wasmtime.dll at module init
Symptom. First request returns a 500, with a FileNotFoundException whose message begins:
wasmtime.dll not found next to the Checkpoint.Core assemblyCause. The NuGet consumer-side targets file that copies wasmtime.dll into your build output didn't fire. As of Checkpoint.Core 0.2.2+, the file ships at buildTransitive/net462/ and is imported automatically by both direct and transitive PackageReference consumers as well as packages.config consumers.
Fix.
- Upgrade to
KyaOs.Checkpoint0.2.2 or later. Versions 0.2.0 and 0.2.1 shipped the targets file atbuild/only, which NuGet skips for transitive consumers — a known bug fixed in 0.2.2. - Install
KyaOs.CheckpointorCheckpoint.AspNet, not bareCheckpoint.Core. The targets file lives in the Framework adapter's transitive graph; a project that references onlyCheckpoint.Coredirectly won't pull it in. - If the error persists after upgrading, run
msbuild /verbosity:detailedand search the log forCheckpoint.Core.targets. A missing import means NuGet's targets graph isn't being walked by your project type — open an issue on agent-shield with a minimal repro.
Supported versions
| Runtime | Versions |
|---|---|
| ASP.NET Core | .NET 6, 7, 8, 9 |
| .NET Framework | 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1 |
.NET Framework requires a 64-bit host process (Windows Server IIS or Azure App Service B1+).