Checkpoint.Core
1.7.4
dotnet add package Checkpoint.Core --version 1.7.4
NuGet\Install-Package Checkpoint.Core -Version 1.7.4
<PackageReference Include="Checkpoint.Core" Version="1.7.4" />
<PackageVersion Include="Checkpoint.Core" Version="1.7.4" />
<PackageReference Include="Checkpoint.Core" />
paket add Checkpoint.Core --version 1.7.4
#r "nuget: Checkpoint.Core, 1.7.4"
#:package Checkpoint.Core@1.7.4
#addin nuget:?package=Checkpoint.Core&version=1.7.4
#tool nuget:?package=Checkpoint.Core&version=1.7.4
Core AI agent detection engine for .NET. Detects AI agents (Claude, ChatGPT, Gemini, etc.) via user-agent patterns, header analysis, and behavioral signals. Platform-agnostic — use with any .NET HTTP server, including ASP.NET Core (via Checkpoint.AspNetCore) and classic .NET Framework 4.6.2+ (via Checkpoint.AspNet).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- BouncyCastle.Cryptography (>= 2.6.2)
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- System.Net.Http.Json (>= 8.0.1)
- System.Text.Json (>= 8.0.5)
-
net8.0
- BouncyCastle.Cryptography (>= 2.6.2)
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- System.Text.Json (>= 8.0.5)
- Wasmtime (>= 44.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Checkpoint.Core:
| Package | Downloads |
|---|---|
|
Checkpoint.AspNetCore
ASP.NET Core middleware for AI agent detection and policy enforcement. Drop-in middleware that detects AI agents, enforces policies from the Checkpoint dashboard, and blocks/redirects automated traffic. The .NET equivalent of @kya-os/checkpoint-express. |
|
|
Checkpoint.AspNet
ASP.NET (System.Web) HTTP module for AI agent detection and policy enforcement. Drop-in IHttpModule that detects AI agents using the same Rust-compiled WASM engine as Checkpoint's Next.js, Express, and .NET Core packages — classic ASP.NET / MVC 5 / Web API 2 / Web Forms consumers get identical detection behavior to modern .NET consumers. Register via Web.config; zero code changes required. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.7.4 | 70 | 8/4/2026 |
| 1.7.3 | 161 | 8/3/2026 |
| 1.7.2 | 119 | 8/3/2026 |
| 1.7.1 | 106 | 8/3/2026 |
| 1.7.0 | 1,148 | 7/23/2026 |
| 1.6.1 | 209 | 7/22/2026 |
| 1.6.0 | 1,852 | 7/2/2026 |
| 1.5.1 | 339 | 6/23/2026 |
| 1.5.0 | 195 | 6/19/2026 |
| 1.4.3 | 163 | 6/19/2026 |
| 1.4.2 | 183 | 6/16/2026 |
| 1.4.1 | 187 | 6/16/2026 |
| 1.4.0 | 193 | 6/15/2026 |
| 1.3.1 | 156 | 6/12/2026 |
| 1.3.0 | 163 | 6/12/2026 |
| 1.2.3 | 190 | 6/11/2026 |
| 1.2.2 | 176 | 6/10/2026 |
| 1.2.1 | 157 | 6/10/2026 |
| 1.2.0 | 172 | 6/10/2026 |
| 1.1.0 | 162 | 6/8/2026 |
1.7.4: report an absolute url for KTA site-visit hostname attribution
Patch — additive, no wire/API breaks, no detection/verification behaviour change.
Both adapters previously sent only the request path to the log-detection context
block, so KTA's site-visit reporting always saw hostname "unknown" for .NET-plane
traffic. RequestContext.AbsoluteUrl (new) carries scheme+host+path+query for
reporting only; RequestContext.Url / DetectionEvent.Path stay path-only, since
Url feeds the embedded engine's RFC 9421 @path signature-derived component and
making it absolute would corrupt every signed-request signature base. See
CHANGELOG.md for detail.
1.7.3: corrects the 1.7.2 release notes — 1.7.2 changed an enforcement default
IMPORTANT — 1.7.2 silently changed a runtime default. Its notes said "Patch — no
API/wire change", which was true of the API surface but wrong about behaviour.
CheckpointOptions.OnDetectionUnavailable changed from Allow to Baseline (#3425 /
#3442). No API moved, so the wording was defensible, but the runtime posture did.
This release ships no behaviour change of its own; it exists to say so.
WHAT BASELINE DOES. When detection cannot run — WASM cold start, a pre-enforcement
step throwing, a persistently unavailable pipeline — the engine never decided
agent-vs-human. Allow passes the request through. Baseline applies your configured
OnAgentDetected action as if an agent HAD been detected, which means it also
applies to humans.
WHO IS AFFECTED. All three must be true:
1. you upgrade to 1.7.2 or later, AND
2. OnAgentDetected is Block, Instruct, Challenge or Redirect, AND
3. you never set OnDetectionUnavailable explicitly.
If OnAgentDetected is Log or Allow — including the unset default, which is Log —
nothing changes for you: those return without enforcing.
NOT ONLY COLD START. The option cannot distinguish a warming pool from a pipeline
that stays down. Under Allow a sustained detection outage degraded to pass-through
and the site stayed up. Under Baseline the same outage enforces for as long as it
lasts, so a detection outage can become a site outage. Earlier documentation
described this exposure as warm-up-bounded; it is not.
TO RESTORE THE PREVIOUS BEHAVIOUR, set OnDetectionUnavailable = Allow explicitly:
ASP.NET Core options.OnDetectionUnavailable = DetectionUnavailableBehavior.Allow;
net462 <add key="Checkpoint:OnDetectionUnavailable" value="Allow" />
Fail-closed is the defensible default for a security gate, so Baseline is retained
deliberately. Choose Allow where never interrupting a human matters more than an
agent briefly slipping through un-enforced.
1.7.2: dependency floor fix for .NET Framework consumers (early-access patch)
Patch — no API/wire change. Ships the Microsoft.Extensions / System.Text.Json
dependency-floor drop to patched 8.x, so classic .NET Framework (net462) consumers
upgrade without pulling the netstandard2.0 10.x transitive polyfill set. This fix is
described in 1.7.1's notes below, but the PUBLISHED 1.7.1 package does not contain it
— the floor change merged just after the 1.7.1 publish fired, so 1.7.1 shipped with
the old 10.0.9 floor. .NET Framework consumers should use 1.7.2 or later; net8.0+
consumers are unaffected either way. System.Text.Json stays at 8.0.5 for the
CVE-2024-43485 fix.
1.7.1: accumulated changes since 1.7.0 (early-access patch)
Patch — additive surface, no wire/API breaks, no migration. Bundles the src/
changes that landed after 1.7.0. We bump MINOR only at milestones while the SDK
is in early access with a single pilot consumer, so additive API may ship in a
patch; it never breaks existing callers. Both adapters now send the detected
agent's name/class/confidence on the challenge block so hosted consent names the
actual agent (display-only; DelegationAnchorRequest gains DetectedAgentName /
DetectedAgentClass / DetectedConfidence, BuildAsync takes them as optional
trailing parameters). net462 hosts get a supported per-request verdict accessor
(CheckpointHttpContextExtensions). The Microsoft.Extensions / System.Text.Json
dependency floor drops to patched 8.x so .NET Framework consumers upgrade without
pulling the 10.x transitive polyfill set. Also: redirect honoured on list matches
and sub-threshold detections recorded; credential-verification blocks preserved in
composed policy; agent-facing docs URL fixed; agentshield naming residue cleaned.
Engine: fingerprint/behavioural/TLS signal details, header signals routed by a
stable discriminant with per-header confidence, real verification trace; embedded
kya-os-engine.wasm (+ cedar) rebuilt with the drift SHA pin. Zero customer code
changes to adopt. See CHANGELOG.md for per-change detail.
1.7.0: enforcement.policyId reported for composed-Cedar decisions
Minor — additive; no wire/API breaks. When the composed-Cedar engine decides a
verdict, DecisionMapping.Apply now stamps the deciding rule's authored Cedar @id
onto the new DetectionResult.PolicyId, both adapters thread it onto
DetectionEvent.PolicyId, and the log-detection report emits it as
enforcement.policyId — the field the dashboard ingest stamps onto
detections.policy_id. Before this release every .NET-plane decision landed
unattributed, so the /policy page counters never moved for .NET traffic.
Null (non-composed decision, or a decision carrying no id) keeps the key off
the wire, byte-identical to prior payloads.
1.6.1: verified signed agents carry their vendor identity on AgentInfo.Type (#3631)
Patch, no API/wire/DB change to the .NET packages. SignatureVerificationHelper now
stamps the verified agent IDENTITY (e.g. "ChatGPT") onto AgentInfo.Type instead of
the verification protocol token ("rfc9421") when the heuristic detector did not
pre-classify the request. The method is still conveyed via VerificationMethod=Signature;
this makes the emitted agent_type self-consistent, so verified signed agents (e.g.
ChatGPT Agent, which signs with a vanilla browser User-Agent) are attributed to their
vendor. Deny-by-agent-name is unaffected (AgentInfo.Name unchanged); only a deny list
containing the literal "rfc9421" changes behaviour. (The data-driven ingest
attribution + agent_types.signature_vendor_aliases migration ship on the web side,
not in these NuGet packages.)
1.6.0 — Branded auth host (B1 #3644) + verified delegation holder (C1 #3663) + C-trust cart-handler sample (#3689). Additive, no wire/API breaks; new public field + optional BuildAsync parameter. See CHANGELOG.md for details.
1.5.1 — net462: warm trusted-root did:web over TLS 1.2 (#3584)
Patch — no API, wire, or DB change. net462 hosts pinned to httpRuntime
targetFramework < 4.7 default outbound HttpClient TLS to 1.0/1.1, which
TLS-1.2-only issuers (e.g. Vercel-hosted did:web) reject — so the resolution
warmer failed to fetch the issuer did:web document and every presented
delegation failed closed (did-unresolvable → re-challenge loop). The warmer
now opts the process into TLS 1.2 before its HttpClients open a connection
(additive, idempotent; a no-op on net8, which already negotiates 1.2/1.3).
1.4.3 — engine: rfc9421 verifier fix (#3474)
Patch — rebuilds the embedded WASI engine (kya-os-engine.wasm + cedar variant)
to pick up the RFC-9421 HTTP-message-signature verifier fix from #3474. No API,
wire, or DB change; cross-runtime parity was green on #3474 with no fixture
changes. The EmbeddedWasmDrift SHA pin is updated to the rebuilt artifact.
1.4.2 — Dual-accept KYA-OS + MCP-I verification methods
Additive — no API, wire, or DB changes. Ships the dual-accept verification work
(#3418) that merged AFTER 1.4.1 was cut, so it was not in the published 1.4.1.
Read-side accept-both: the engine's canonical kyaos_handshake value now resolves to
the same VerificationMethod.McpIHandshake enum as the legacy mcp_i_handshake, so an
agent verified by EITHER method flows through the same verified-delegation path.
Emitters are unchanged (still emit the legacy canonical). No migration.
1.4.1 — Fetcher-compatible 200 challenge envelope (opt-in)
Additive, no API breaks; default behaviour unchanged. The §8.1 Delegation challenge
is a 401, but AI-agent fetchers (e.g. Claude-User WebFetch) drop 4xx bodies, so the
consent_uri never reaches the user. This adds a body-readable HTTP 200 variant of the
SAME challenge for cooperative / self-identifying agents.
- New Checkpoint:DelegationChallengeMode { Spec401 (default), Negotiated, Always200 }
(Web.config on net462; IConfiguration on net8). Negotiated serves the 200 envelope
for a cooperative agent — the KYA-Accept-Challenge request header OR a detected
interactive ai_agent — and the spec 401 otherwise. The HTTP Accept header is NEVER
a selector (a detected agent is never demoted by Accept). Default Spec401 keeps the
401 wire, so existing deployments are unchanged until a project opts in (#3426/#3428).
- The 200 envelope carries the SAME JSON body as the 401 (KYA-Action: challenge,
KYA-Auth-Url / Link hints; no WWW-Authenticate / Retry-After). challenge_proof
binds the body, not the envelope, so the org-signed proof verifies at 200 or 401.
- net462 Web.config binder now has a real test project (Checkpoint.AspNet.Tests),
closing the gap that let 1.4.0's ResourceOrgDid binding ship untested (#3430).
- Assurance projection + delegation challenge host-origin hardening (#3287).
1.4.0 — Delegation verification hardening + live did:web Ed25519
Hardens the standalone (Authorization: Bearer) delegation-verify path and proves
it on the real target. Additive — no API changes; the §8.1 challenge wire stays
opt-in (Checkpoint:EnableDelegationChallengeWire).
- did:web resolution now extracts Ed25519 (OKP) keys, not only P-256, so the
org's Ed25519-signed delegations verify against the live published key
(DidWebResolver / JsonWebKey2020Validator, #3395). The same key is published as
two methods — #key-1 (publicKeyMultibase) and #key-1-jwk (publicKeyJwk) — and
delegations sign kid=#key-1, which the engine matches by EXACT id, so the
resolver surfaces BOTH (multibase 0xed01/base58btc decode + JWK), each by exact
id (#3399). Proven non-mocked against the live shape: a real Ed25519 did:web
document → the real resolver → the WASI engine's verifyDelegation → Permit.
- classic ASP.NET (net462) Web.config now binds the Bearer-verify config —
Checkpoint:TrustedDelegationRoots, Checkpoint:StatusListWarmTargets, and
Checkpoint:ResourceOrgDid — so the resolution warmer primes and a presented
delegation can match its audience on a Framework host. Without these the verify
path was dead config on net462 (a forged credential still 403s; only the valid
→ 200 leg was affected).
- StatusList2021 revocation is wired into the host context so is_revoked fires;
the revoked map is keyed on the bare statusListCredential the engine reads,
and a presented credential the host can't confirm fails CLOSED (#3378, #3384).
- A presented credential the engine cannot verify NEVER demotes to an anonymous
Permit — it fails closed carrying the engine's §9 kyaos/* code; the legacy
self-asserted x-agent-did self-mint is retired (#3370).
- ASP.NET Core: a kyaos/* delegation reject renders 403 in the default plaintext
mode (was 200) (#3377).
- Delegation resolution moved OFF the request/enforce path: a background warmer
pre-resolves the configured trusted roots + status lists, so the request path
is a cache read with zero outbound I/O (no attacker-triggerable blocking
fetch); a not-yet-warm resolution fails closed with a retryable kyaos/*
pending code (#3386).
1.3.1 — Web.config reader accepts PolicyCacheTtlMinutes = 0
The classic ASP.NET Web.config reader required a positive
Checkpoint:PolicyCacheTtlMinutes and silently ignored 0, so a Framework host's
policy-propagation floor was 1 minute. The guard now accepts 0, matching the
ASP.NET Core options binder which has always honored it: 0 disables policy
caching entirely — every request fetches the policy (bounded by the 3s fetch
cap + 10s negative cache). Intended for demo/example sites; production hosts
should keep the 5-minute default. Negative and non-numeric values are still
ignored.
NOTE for hosts that already had value="0" in Web.config: that value was
previously ignored (5-minute default applied); from this release it is honored
and the host switches to fetch-per-request.
1.3.0 — Delegation challenge wire (draft-kya-http-02 §8.1, opt-in)
Adds the spec §8.1 Delegation challenge as an opt-in, version-gated wire for
a composed-policy `challenge` verdict, replacing the legacy `200 + KYA-Action:
challenge` MCP-I step-up. Breaking wire change — OFF by default for one cycle.
- New shared `Checkpoint.Core.Http.DelegationChallengeBuilder` emits the
byte-exact wire (401, `WWW-Authenticate: Delegation` with frozen param
order + companion RFC 9728 `Bearer` for `kind=delegation`, `Retry-After`,
`Cache-Control`, and the `kyaos` JSON body + four-element `instructions`),
validated against the H2.0 golden fixtures. The net462 adapter and the
net8 middleware (#3250) share it so they cannot drift.
- `Checkpoint.AspNet.CheckpointModule` emits the new wire when
`CheckpointOptions.EnableDelegationChallengeWire` is set (web.config:
`Checkpoint:EnableDelegationChallengeWire`). New `AuthorizationHost`
option (`Checkpoint:AuthorizationHost`) sets the consent/pickup origin;
falls back to the request host.
- `sid` and `challenge_proof` are placeholders pending live bouncer/sessions
anchor registration (#3246); today's emit is the minimal-shaped challenge.
1.2.3 — Cold-start fail-open hardening (.NET)
Closes the post-deploy window in which the first agent requests after an
app-pool recycle could be served un-enforced (and, in the observed CI
failure, as a header-less bare 200 with no KYA-* signal). Three behavioral
changes (four new public members); additive and opt-in — default behavior
is preserved.
- Eager startup warm-up of the WASM runtime (WasmAgentDetector.WarmupAsync)
+ policy cache, off the request hot path — CheckpointModule.Init() and a
CheckpointWarmupService hosted service for the net8 adapter. The runtime
previously initialized lazily on the first AnalyzeAsync; warming at
startup drives the cold window toward zero.
- Observable fail-open: the fail-open catch now always stamps a
`KYA-Failopen: true` response header, so a fail-open is never an
invisible bare 200 (operators + the post-deploy smoke gate can see it).
A detection-unavailable result also stamps `KYA-Detection: unavailable`.
- OnDetectionUnavailable posture (default Allow at 1.2.3; the default
changed to Baseline in 1.7.2 - see the 1.7.3 note at the top): when
detection itself can't run, hosts may opt into Baseline to apply the
configured OnAgentDetected action instead of allowing the request through.
DetectionResult.DetectionUnavailable surfaces the WASM cold-start
failure that previously masqueraded as a silent "Human".
Migration: zero customer code changes required. The new public surface
(CheckpointOptions.OnDetectionUnavailable, DetectionUnavailableBehavior,
DetectionResult.DetectionUnavailable, WasmAgentDetector.WarmupAsync) is
additive and defaults to today's behavior. To fully close the agent-slip
gap on an enforcing site, set OnDetectionUnavailable = Baseline.
1.2.2 — Scope-gated challenge: forward granted_scopes + render Challenge
Two changes that let a composed /policy-compose bundle scope-gate a CHALLENGE
("challenge a known agent unless the user delegated scope S for this route"):
- The SDK now FORWARDS the engine-verified delegation scopes
(VerifyResult.detectionDetail.grantedScopes, embedded engine #3187) into
AuthorizeInput.grantedScopes, so a `unless { context.granted_scopes.contains
("S") }` carve-out enforces in-process. Empty/no-delegation posture omits the
key (byte-shape parity with the TS projection); a forged delegation forwards
nothing.
- A composed-Cedar Challenge decision now RENDERS an MCP-I step-up: 200 +
KYA-Action: challenge + X-Checkpoint-Decision: challenge whose JSON body
points the agent at the bouncer/authorize URL (mirroring the Instruct writer
via the shared McpInstructBuilder), on BOTH adapters (net8 + net462), instead
of collapsing to Block. The engine's Challenge params (nonce/audience/...)
arrive empty in-process, so the writer keys off the authorize URL.
Migration: zero customer code changes. Affects only projects whose composed
bundle scope-gates or emits Challenge (generated Cedar predominantly emits
Permit/Block).
1.2.1 — Web.config policy-cache TTL knob (classic ASP.NET)
Adds a `Checkpoint:PolicyCacheTtlMinutes` Web.config appSetting so classic
ASP.NET / IIS (Checkpoint.AspNet) hosts can shorten the policy-cache window
(default 5 min) — e.g. set it to 1 for rapid dashboard rollout. The SDK is
pull-only with no server-push invalidation, so this is the only lever a
Web.config-configured host has to speed up picking up a deployed policy /
composed-Cedar change short of an app restart. Must be a positive integer;
ignored otherwise. (.NET Core hosts already set PolicyCacheTtlMinutes via
IOptions<CheckpointOptions>.)
Also refreshes stale doc comments that still described composed Cedar as
"inert on .NET Framework" — it has ENFORCED on net462 since 1.2.0 (the
NativeCedarCompiler P/Invoke path). No behavior change from the doc edits.
Zero customer code changes to adopt.
1.2.0 — Composed-policy enforcement goes live (net8 AND net462) + engine refresh
Three things ship here that 1.1.0 staged but did not publish:
1. Composed /policy-compose Cedar enforcement is now WIRED INTO the
net8 request path (CheckpointMiddleware step 5b, #3143). It stays
shadow-first + fail-open: a project's bundle only REPLACES the
structured decision when its engineEnforcementEnabled gate is acting;
otherwise it shadows and the structured decision stands, and any
compile / authorize fault falls open. 1.1.0 shipped the evaluator as
"foundation only" (not wired); this release activates it.
2. The .NET Framework (netstandard2.0 / net462) cedar path now ENFORCES
too, via NativeCedarCompiler — the hand-rolled wasmtime.dll P/Invoke
peer of the net8 CedarCompiler, driving the same embedded cedar engine
with the same single-instance + handle model and the same shadow-first
+ fail-open posture. Classic ASP.NET / IIS (Web Forms, Web API 2) hosts
now get composed-policy enforcement at parity with net8 (#3076). A host
without a usable wasmtime.dll degrades to detection-only.
3. Embedded detection WASM refreshed from current kya-os-engine main —
now includes the #2869 "KYA-OS HTTP Binding" engine verification path,
which the 1.0.2-pinned binary in 1.1.0 predated. Cross-runtime parity
(rust + node-wasm + edge-wasm + dotnet-wasi) stays CI-gated and green.
Embedded WASM SHA-256:
adf369ea61565f1d13b17a698c97791ce62dabcc94942644d4731d2eb26b04db
(was 55e072f3ef71a2d548f935a292a07f8ab983eb4afa7ba5323f750b38845de33f
in 1.0.2 / 1.1.0; pinned in Checkpoint.Core.Tests/Detection/
EmbeddedWasmDriftTests.cs#ExpectedSha)
Migration: zero customer code changes. Enforcement remains opt-in per
project (deploy a bundle + enable engineEnforcementEnabled); consumers
who do neither are byte-identical to 1.1.0 behavior.
────────────────────────────────────────────────────────────────────
1.1.0 — Cedar composed-policy foundation (.NET)
Brings the .NET adapters onto the shared composed-policy SSOT, alongside
the Express / Next.js / gateway runtimes: a project's deployed
/policy-compose Cedar bundle can be evaluated in-process via the embedded
engine. Cross-runtime parity with the TS runtimes is CI-gated
(AuthorizeInputProjectionParityTests).
Shadow-first + fail-open: composed enforcement is opt-in
(engineEnforcementEnabled defaults false), so existing consumers are
byte-identical until they deploy + enable a bundle, and any compile /
authorize fault falls open to the structured decision.
- ComposedPolicyEvaluator + AuthorizeInputProjection: fact ->
AuthorizeInput projection and compile-once / authorize-many
evaluation of a tenant's Cedar bundle (#3111, #3113).
- DetectionResult.EngineBlocked: the engine's RAW block verdict,
preserved before structured policy so the mcp_i_handshake optimistic
override keys off the engine's verification result, not a post-policy
allow-list — a forged handshake the engine blocked can no longer
reach Cedar as a verified delegation (#3113).
Foundation only: the evaluator is not yet wired into CheckpointMiddleware
(net8) / CheckpointModule (net462) — composed-policy enforcement
activates in a follow-up. Composed Cedar requires the net8 engine path;
the netstandard2.0 / net462 path short-circuits to no-policy until the
Framework cedar path lands.
Migration: zero customer code changes required. The new public types
(ComposedPolicyEvaluator, AuthorizeInputProjection, ICedarCompiler,
DetectionResult.EngineBlocked) are additive; existing behavior is
unchanged.
1.0.3 — Surface true enforcement outcomes on the dashboard
The .NET counterpart of the JS reporter fix shipped in
@kya-os/checkpoint-express + @kya-os/checkpoint-nextjs 1.4.0 (#2843).
Before 1.0.3 the .NET adapters posted detections to
/api/v1/log-detection without an `enforcement` block, so every
redirect / instruct / block applied by CheckpointModule (net462) or
CheckpointMiddleware (net8) landed in the dashboard as "unknown" on
the OutcomesBar / chart series — the operator could see traffic but
not what their middleware actually did with it.
Hardware World was the visible failure: with OnAgentDetected=Redirect
configured, ChatGPT/Claude hits 302'd to the connect page but the
dashboard never showed a redirect bar.
Fix: the adapters now thread the applied action into
`DetectionEvent.EnforcementAction` (+ optional Reason) at every
short-circuit and on the generic pass-through:
- Policy short-circuit: instruct | redirect | block
- Local config Block: "block" (+ result.BlockReason on policy block)
- Local config Instruct: "instruct"
- Local config Redirect: "redirect"
- Local config Redirect with non-absolute McpServerUrl: falls through
to "block" — the reported action reflects what HAPPENED (block),
not what was configured (redirect), so the chart doesn't show a
redirect that never occurred.
- Pass-through (Log / Allow): "log" in observe-mode (OnAgentDetected
= Log), "allow" otherwise. Mirrors the JS reporter's
`extractEnforcement()` Permit branch.
Canonical wire-action strings live in the new
`Checkpoint.Core.Configuration.EnforcementActions` static class so
both adapters report identical values — a typo would silently mis-
bucket as "unknown" rather than surface as the true outcome.
Migration: zero customer code changes required. The public API
(IAgentDetector, DetectionResult, CheckpointOptions, CheckpointModule,
CheckpointMiddleware) is unchanged. Bump the package version in
your csproj or packages.config; on the next request the dashboard
starts showing real redirect / instruct / block bars instead of
collapsing everything into "unknown".
8 new middleware tests + 6 new payload tests assert the action /
reason mapping for every branch (Block / Instruct / Redirect /
Redirect-fallthrough / Log / Allow / Policy-Redirect / Policy-Block).
1.0.2 — P0 latency hotfix: reactor-style WASM (Hardware-World-Hotfix-1)
CRITICAL FIX. Customer-reported regression on production deployment:
Hardware World (.NET Framework 4.8 + IIS + Web Forms) saw 22× median
slowdown and 50-second worst-case TTFB after installing 1.0.1.
Root cause: the embedded WASM shipped in 1.0.0–1.0.1 was a WASI
command-style module (`_start` entry point with stdin/stdout file
piping). Every HTTP request rebuilt the wasmtime Store/Linker/Instance,
did 6 filesystem operations, and — most importantly — re-ran every
`once_cell::Lazy` static in the Rust engine. With 123 `Regex::new`
calls in the pattern tables alone, per-call cost was ~84ms on the
fastest configuration (Apple Silicon + .NET 8 + SSD). On Windows + IIS
+ .NET Framework with NativeWasmtimeRuntime's P/Invoke layer, the
floor rose to 150-300ms and under concurrent load .NET Framework's
threadpool injection rate (~1-2 new workers/sec) cascaded into the
50s tail the customer observed.
Fix: the embedded WASM is now a reactor cdylib with three callable
exports — `engine_alloc`, `engine_dealloc`, `engine_verify_json`. The
host (both WasmtimeDotnetRuntime on net6.0+ and NativeWasmtimeRuntime
on netstandard2.0) instantiates ONCE and marshals JSON in/out via
linear memory. The engine's `Lazy` statics initialise once per WASM
instance and stay alive across calls.
Bench numbers (PerfBench harness, macOS .NET 8):
Metric 1.0.1 1.0.2 Improvement
----------------------------------------------------------------
Sequential median 84.1 ms 0.1 ms 840×
Sequential max 96.2 ms 0.5 ms 192×
Concurrent max (50 workers) 1842 ms 144 ms 13×
Throughput 12 c/s 6623 c/s 552×
Production on Windows + .NET Framework will see proportionally larger
wins because the contention amplification this avoids was higher
there.
Threading model: wasmtime Stores are not thread-safe. Both runtimes
keep one Store + Instance per thread via ThreadLocal<T>. First
call on each thread pays the lazy-init cost (~80ms); every subsequent
call on the same thread is <5ms. Under steady IIS load the
threadpool converges to a stable working set.
Other changes:
- Dropped Task.Run wrapper in WasmAgentDetector.AnalyzeAsync — the
per-call work is now CPU-bound and tiny; the threadpool detour
cost more than it saved.
- Dropped temp-file WASI stdin/stdout (no longer needed).
Migration: zero customer code changes required. The public API
(IAgentDetector, DetectionResult, CheckpointOptions, CheckpointModule)
is unchanged. Upgrade from 1.0.1 → 1.0.2 by bumping the package
version in your csproj or packages.config; no Web.config changes,
no Program.cs changes, no Web Forms code changes.
Embedded WASM SHA-256:
55e072f3ef71a2d548f935a292a07f8ab983eb4afa7ba5323f750b38845de33f
(was 800a314eb719bad54e94ee2fc94261110b7810be461adf83d4e6ea41eaf882ec
in 1.0.1; bump pinned in Checkpoint.Core.Tests/Detection/
EmbeddedWasmDriftTests.cs#ExpectedSha)
1.0.1 — Embedded engine refresh: post-#2685 TS-canonical pattern names
The embedded kya-os-engine.wasm shipped in 1.0.0 was built before
the Engine-Pattern-Codegen-Retirement-1 work (#2685) landed on main.
That work made the TS pattern registry the single source of truth and
codegen'd the Rust pattern table from it, which renamed several
canonical pattern IDs to match the TS convention:
GPTBot → "Openai Gptbot"
ClaudeBot → "Anthropic ClaudeBot"
(and similar vendor-prefixed forms across the AI crawler tier)
These names surface inside DetectionResult.DetectedAgent.Name,
DetectionResult.AgentType, and inside the detection signals + reasons
arrays consumed by the dashboard. The 1.0.0 .NET cohort was emitting
the pre-#2685 names; the Next.js + Express cohort (on
checkpoint-wasm-runtime@1.5.x) was emitting the post-#2685 names. The
delta showed up as detection-label drift between the two cohorts in
the dashboard.
1.0.1 re-bakes the embedded WASM from current main (kya-os-engine post
#2685) so every .NET deployment surface emits the same canonical
pattern names as the rest of the workspace. No public API change; no
new config knobs; no behavior change beyond the label correction.
Validation: this release is the first checkpoint-dotnet build covered
by the cross-runtime parity gate (#2708 / Cross-Runtime-Parity-Dotnet-
Coverage-1). The 4-runtime assert (rust + node-wasm + edge-wasm +
dotnet-wasi) catches exactly this class of stale-embedded-engine drift
before publish, so future .NET releases stay in lockstep automatically.
Embedded WASM SHA-256:
800a314eb719bad54e94ee2fc94261110b7810be461adf83d4e6ea41eaf882ec
(was 1626006e01b24a71de0f7476cb90349f06f80c0b52436a34e9dfdce470aa50d1
in 1.0.0; bump pinned in Checkpoint.Core.Tests/Detection/
EmbeddedWasmDriftTests.cs#ExpectedSha)
1.0.0 — Engine refresh: kya-os-engine replaces agentshield-core
The embedded WASM detection engine migrated from the legacy
agentshield-core / agentshield-wasi crates (last refreshed at v0.1.1)
to kya-os-engine — the same engine shipping in
@kya-os/checkpoint-wasm-runtime@1.4.x for Next.js + Express middleware
customers. .NET joins as the third host runtime on the unified engine.
The WASM binary, produced by rust/scripts/build-engine-wasi.sh from the
new kya-os-engine-wasi wrapper crate, drops from 7.2 MB (legacy) to
1.31 MB post wasm-opt — a 5.5× shrink. Lockstep upgrades for .NET
customers preserve every public API (IAgentDetector, DetectionResult,
CheckpointOptions, CheckpointModule) so existing customer code recompiles
unchanged.
What .NET customers gain:
- Tier 2 vendor IP + UA cross-match (16 vendor bots — Perplexity,
OpenAI x3, Anthropic x3, Google x3, Apple, Bing, DuckDuckGo x2,
Common Crawl). Surfaces via the new DetectionResult.VerifiedTier /
VerifiedVendor / VerifiedProtocol attribution fields.
- Tier 3 calibrated per-pattern confidence (replaces the legacy
single-knob ConfidenceThreshold misconfiguration footgun).
- Monitor-default Tier 3 behaviour: the engine classifies but does
NOT short-circuit a Block on a Tier-3 UA match. Tenant policy
decides enforcement. Opt-in to engine-default blocking via the new
CheckpointOptions.Tier3Action knob.
The .NET package's existing C# Tier 1 verifiers (ChatGptSignatureVerifier
RFC 9421, KyaAgentVerifier MCP-I JWS) are unchanged and continue to
pre-empt the WASM dispatcher for signed traffic.
Added:
- CheckpointOptions.Tier3Action (Monitor / Block / Challenge — default
Monitor)
- DetectionResult.VerifiedTier / VerifiedVendor / VerifiedProtocol
- kya-os-engine.wasm replaces agentshield-detect.wasm as the embedded
resource. Build via rust/scripts/build-engine-wasi.sh + commit the
refreshed bytes alongside the SHA pin update in
Checkpoint.Core.Tests/Detection/EmbeddedWasmDriftTests.cs.
Migration from 0.4.0:
- Existing CheckpointOptions configurations work unchanged.
- Empty-policy customers behave identically to 0.4.0 (Permit by default
on known agents — no breaking change).
- Customers wanting engine-level Tier 3 blocking explicitly set
Tier3Action.Block on CheckpointOptions.
Breaking changes: none at the public API surface. The embedded WASM is
replaced but the host code preserves the IAgentDetector + DetectionResult
+ CheckpointOptions contracts. The legacy wire format (detect action with
DetectionInput { headers, ip, method, url, tlsFingerprint }) is gone;
this is internal to WasmAgentDetector and not customer-observable.
0.4.0 and earlier — see CHANGELOG.md in the repository for the pre-1.0
history (https://github.com/Know-That-Ai/checkpoint/blob/main/packages/checkpoint-dotnet/CHANGELOG.md). Moved out of this property
in 1.7.3: NuGet caps ReleaseNotes at 35,000 characters and the full
history no longer fits.