The language implementation is 1.0-grade: it self-hosts, the full suite is green (1,070 conformance + 301 negative, 1,371 tests at 100% pass; both gates CI-blocking), the concurrency model is race-free (thread-safe GC, ThreadSanitizer-verified) and the build is reproducible byte-for-byte. The release-candidate label is deliberate: the project's headline goal is verifiable trust, and that program is now most of the way through its 12-step roadmap. Deterministic compiler IR (Step 3), the reproducible end-to-end binary (Step 4), the independent bootstrap path (Step 5) and the diverse double-compilation gate (Step 6, clang-18 vs clang-19, 102/102 IR files identical) are all per-commit CI gates, no longer manual checks. kern audit-caps makes the audit surface the capability grants, not the code (Step 8). Capability enforcement is machine-checked in Rocq with zero admits (Step 11), the lexer bisimulation likewise. The verification dossier and the Kern Verified mark mechanism exist (Step 12). Step 10, the verifiable supply chain, closed on 2026-09-02 when package signature verification landed fail-closed, so nine of the twelve steps are now done and gated. Still open: the whole-program soundness argument is reviewable and test-backed but not yet machine-checked, and the one piece that cannot be produced from inside the repository, an independent external audit, has not yet been commissioned. The live TRUST.md and ROADMAP.md track exactly what is and isn't verified; 1.0.0 final follows a soak. The flagship privacy claim, PersonalData<T> to AI is a compile error, extends to every sink: display, file, database and HTTP, not just the LLM call.
Everything that has landed.
Newest first. This is the full record behind the claims on the home page, including the audits that found our own bugs. Findings are named rather than hidden, and corrected when they turn out to be wrong.
Four threads of work landed in the same week. Multi-vCPU guests. The microVM monitor gained SMP: microvm_create_smp spawns a VM with n vCPUs, each its own KVM vCPU on its own host thread, with per-vCPU CPUID topology and an Intel MP 1.4 floating-pointer table the monitor writes so the guest kernel discovers every core. Block-image volumes mount into the guest under the same capability that gates the VM itself, with a copy-on-write rootfs so tenants share a base image without writing to it, and an ext4 image writer, written in pure Kern, that produces the disk from a directory. Scoped Cap<Fs>. fs_scope(fs, root) confines a filesystem capability to a single directory: every path is resolved component by component via openat(O_DIRECTORY|O_NOFOLLOW), so an absolute path, .. or a symlink pointing outside is Err, never a read or write outside. The root is pinned by device and inode, so renaming the directory and planting an impostor at the same path is refused. Scopes nest. Generational GC. A nursery collects short-lived values without scanning the full heap, auto-GC is on by default, and a write barrier promotes nursery values stored into old-gen collections. Alongside it: HTTP thread pool, str length cache, GC lock elision, zero-copy str.split, in-place list append (the compiler lowers xs = xs + [e] to an append), and single-pass code emission, taking bootstrap from 35 seconds to 14. C-layer fail-closed sweep. Two systematic passes across every C leaf in HTTP, TLS, sync, event log, KMS, netlink, Redis, MQTT and WebSocket, converting every "succeed on error" path to a fail-closed return. A static-analyser sweep, an init_globals-per-TU fix and a W0003 SSRF lint round out the hardening.
Four modules landed that turn kern from a language you deploy onto a cloud into one you can build a cloud out of, and they share a design decision worth naming. net.s3_server answers the S3 API that net.s3 calls, with buckets and keys validated against traversal and objects stored flat so a request can never escape the root. net.lb is the backend-selection brain: round-robin, least-connections and weighted strategies over an immutable pool, where marking a backend unhealthy gates it out and an all-down pool fails fast rather than dialling a dead host. sys.volume is a block-volume catalog with the safety invariants written into the state machine: a volume is attached to at most one instance, an attached volume cannot be deleted, a snapshot records its parent, and a base volume with live snapshots is protected. sys.fleet is the self-healing loop, diffing the fleet you asked for against the fleet you have and returning the ordered actions to close the gap, including restarting an instance whose heartbeat has gone stale. The shared decision: every one of these cores is pure and deterministic. Selection returns the advanced pool rather than mutating one, an illegal volume transition comes back as data rather than crashing a live host, and reconciliation is a function from desired and observed state to a list of actions. That means the logic is unit-testable without a socket, a disk or a running fleet, which is the difference between a control plane you can reason about and one you can only watch.
The isolation story went from a proof of concept to a multi-tenant platform in one wave. The decision recorded in docs/design/microvm-kern.md was to write the monitor from scratch in Kern rather than orchestrate Firecracker or Cloud Hypervisor, because a multi-tenant isolation boundary that is someone else's binary is where sovereignty stops. The guest. Cap<Vm> is a capability kind only the entry module can mint, so an ambient KVM call is E0404. The engine enters 64-bit long mode, implements the Linux boot protocol and boots an unmodified Ubuntu kernel, which logs over a 16550 UART emulated in Kern; emulating the transmit and receive interrupts made that console interactive, so a shell answers uname over a live session. A virtio-blk device mounts real ext4 and the guest boots straight from /dev/vda with no initramfs, running the distribution's own /sbin/init as PID 1. A tap-backed virtio-net NIC gives it a network, and vm_publish_port DNATs a host port to a guest service over nftables, verified end to end. The platform. Tenants run as one OS process each, the same isolation boundary Firecracker and Fly.io use, so a tenant cannot corrupt a co-tenant through shared in-process state; each gets its own cgroup, Landlock scope and seccomp jailer. Authority is split by capability rather than by convention: spawning and stopping need Cap<Process>, confinement and stats need Cap<Fs>, and only the runner itself mints Cap<Vm>. Every lifecycle transition, created, booted, spawned, stopped, reaped, lands in the same SHA-256-chained event log the compliance trail uses, and microvm_audit_verify checks it independently. The hardening shipped with it, not after. No guest-supplied value forms a host pointer without first being proven to lie inside the guest's RAM; the bounds check was rearranged so a descriptor address near INT64_MAX cannot overflow-trap and abort the monitor; disk DMA is gated on the backing file's real size so a guest cannot write past it; and kill now rejects a non-positive pid, because a failed spawn's -1 reaching a terminate path would have signalled every process on the host. An adversarial test proves host memory just past the guest region survives a hostile write.
An adopter put it plainly: the documentation is what actually gets read, so a document promising a capability the code does not deliver is a false contract. A doc-versus-code audit was run across the README, the agent-facing llms.txt, the internal guide and every stdlib docstring, and it surfaced one critical security bug alongside a batch of guarantees that were narrower in the code than on the page. The critical one is worth stating without softening, because it lands on a module this site listed as shipped: webauthn_verify_assertion returned valid after checking the challenge, the relying-party hash, the user-presence flag and the signature counter, and never verified the signature at all; the imported verifier was dead code. Any request carrying the right relying-party hash and challenge would authenticate as any user, with an arbitrary signature and an unrelated public key. That is a total authentication bypass in a module advertised as phishing-resistant FIDO2. The root cause is structural rather than careless: a WebAuthn signature covers authenticatorData concatenated with the SHA-256 of the client data, a binary message a NUL-terminated Kern string cannot carry, and the existing verify primitive measures its message with strlen, so no primitive in the language could have verified it correctly. The fix was to make the function fail closed, returning invalid with an explicit reason so it can never authenticate without a real signature check, and to flip the conformance test that had been asserting an all-zero signature was valid so it now pins the bypass shut. A binary-safe verifier leaf (ES256 through mbedTLS P-256, EdDSA through libsodium) is scoped as the follow-up; until it lands, passkey verification is honestly advertised as unavailable rather than quietly broken. The rest of the sweep narrowed claims to what the code does: cert_is_self_signed was documented as checking for a known CA while returning subject-equals-issuer, an inverted trust decision; the mTLS module's “peer certificate verification” and “enforced minimum TLS version” are policy checks over fields TLS has already verified, with the minimum version recorded rather than enforced; the SIEM module's plain SHA-256 chain was described as tamper-evident when an unkeyed chain is re-forgeable by whoever writes the log, so its header now points at the keyed chain; hostname validation was documented as an SSRF control when the real control is the resolver guard; and the tracked-nonce helper is bookkeeping, not the cipher's own nonce, so it does not prevent nonce reuse. In llms.txt the flagship SQL-literal rule had been documented under the wrong error code entirely, which means code-generating models were being taught the wrong code for the headline feature; the generator is corrected. A parallel crypto audit found the matching pair: pseudonymise was an unkeyed hash of personal data, and an unkeyed hash of a name, an e-mail or a national ID is dictionary-reversible, so it did not pseudonymise in the GDPR Art. 4(5) sense at all. It is now keyed HMAC-SHA256 with a domain-separated subkey and a version tag, and an empty key is refused rather than silently producing a reversible value. The same pass corrected four places, including this site, that described the event-log chain as BLAKE2b when the code has used keyed HMAC-SHA256 for some time. None of this is comfortable to publish. It is also the only version of a trust claim worth anything: the register names what was wrong, including in the documentation, and the corrections ship with the tests that pin them.
Compile throughput was profiled end to end and three root causes fell out, each fixed without a rewrite. The strlen tax: Kern strings are NUL-terminated, so every length query was O(n), and a compiler slices and bounds-checks the same string constantly. The GC object header already carried a spare uint32 that nothing read or wrote; it is now a memoized strlen, so the first query on a string computes and caches and every later one is O(1). Self-bootstrap user-CPU went from 133.8 s to 37 to 46 s, about 3x, with no layout change and no producer changes. The GC hash: the collector's address-to-liveness table folded address bits with XOR-shifts, which collapses to addr>>4 for the near-constant strides malloc returns, textbook primary clustering. Measured over 44 million inserts, average probe was 14.97 and a single insert probed 123,898 slots. Fibonacci hashing diffuses every input bit into the high word: average probe 0.45, worst case 57. Wall time is unchanged, so this is a tail-latency fix, and it matters most for a long-running Kern server allocating under KERN_AUTO_GC. The prelude: every build force-injected all 146 replaceable-stdlib modules and emitted every function whether the program called it or not, so hello.kern shipped 255 function definitions and 52,002 IR lines for clang to optimise and the linker to throw away. Emission now runs a reference fixpoint over the resolved @kern_ symbols, so unreferenced prelude functions are never emitted at all: 25 definitions, 6,411 IR lines, build user-CPU 1.97 s to 0.40 s. The compiler's own bootstrap deliberately keeps the shake off, so the reproducibility chain is untouched, and the bootstrap fixpoint is still byte-identical generation over generation. The latest round went after collections. list_append is the allocation hot path under strings, parsers and every collection-heavy stdlib function, and profiling a tight append loop showed the cost was not the store but the machinery around it: a mutex taken on every single element even when no second thread exists, a GC header probe per append, and a root slot pushed for a result the caller discards. A monotonic flag now records whether the process has ever spawned a thread, set on the parent side before every thread-creating primitive so no window exists where two threads both read “single-threaded”, and the lock is skipped until that flag flips, after which it re-arms forever. The GC roots moved inside the grow branch, because a no-grow append allocates nothing and therefore cannot trigger a collection. The compiler emits an inline fast path at the call site. Sorting got its own fix: a Kern quicksort was making a runtime call per comparison and per swap, where the values already sit inline in the list's own slots, so a native sort over those slots replaced it. Together, appending is about 4x quicker and sorting a million integers went from 731 ms to 118, with the sort step itself down to roughly 16 ms, which upstream calls Go-class. Verified under GC stress with a collection on every allocation, so nothing is left unrooted.
Kern is now addressable by code-generating models as a first-class consumer. kern check --json and kern build --json emit exactly one JSON object on stdout with the same diagnostic schema (severity, E-code, message, file, line, column, hint), covering the whole build path: import resolution, typecheck, IR streaming, the cross-link refusal and the clang link. kern fix closes the loop by applying the mechanical repairs an agent should not have to reason about, starting with the typechecker's own “Did you mean?” renames; it is safe by construction, re-verifying that the bad token is still exactly at the recorded position before writing and applying edits bottom-up so a same-line fix never shifts a pending column. A generated llms.txt bundle gives a model the whole language surface in one file, counts pulled from source. On the protocol side, three new modules implement Model Context Protocol server and client over JSON-RPC 2.0, and they close the injection hole that MCP normally leaves open: tool arguments arrive as Untrusted<str> and tool results return as Untrusted<str>, so a handler that feeds model-provided input into SQL, shell, HTTP or a file without validating it does not compile (E0303). The same rule now applies to the model itself: ai_complete, ai_api_call and ai_chat return Untrusted<str>, because LLM output is adversarial input by definition, and every wrapper above them propagates the taint. That is the compile-time axis; the runtime axis is a WAF prompt-injection detector covering 27 patterns in five families (instruction override, role hijack, system-prompt extraction, delimiter injection, jailbreak). The language surface grew to match: select over channels with recv, timeout and default arms, which was the largest concurrency gap against Go, plus else if, real atomic sub/and/or/compare-swap, string interpolation over any expression rather than bare identifiers, and main(args) receiving argv. And kern new api <name> now scaffolds a service that actually works: health and root routes on :8080, compiling to a roughly 115 KB binary that answers curl out of the box, on macOS and Linux.
Kern reaches the device tier without a C dependency. sys.hci drives a Bluetooth controller over HCI_CHANNEL_USER, claiming the adapter exclusively the way a from-scratch host stack does, which is what mesh needs because it wants precise control of scanning and advertising rather than sharing with the kernel. It is verified against a real controller: hci_local_version returned HCI 5.2 and matched hciconfig exactly, revision included. sys.ble adds active LE scanning (parsing advertising reports into address, RSSI, flags, local name, manufacturer data and service UUIDs, deduplicated and merged with scan responses) and the advertising bearer that mesh provisioning rides on. On top of that the BLE Mesh stack is complete: network layer with obfuscation, AES-CCM, replay protection, IV index, segmentation and relay; the access layer and a Generic OnOff model for real device messages; Secure Network Beacon; commissioning, revocation and configuration; Heartbeat publication and subscription for topology discovery; Friendship, so a Low Power Node can sleep while a Friend queues its messages; and the Proxy protocol with PDUs and SAR. Provisioning is P-256 ECDH written from scratch in Kern, deliberately on 16-bit limbs rather than 32, because Kern integer arithmetic is overflow-checked and traps, so a 32×32 limb product would abort. It is verified against authority rather than itself: point doubling matches the standard vector in both coordinates, a derived public key matches one generated by OpenSSL, and the shared secret matches openssl pkeyutl -derive. Scalar multiplication is constant-time, which closes the provisioning timing side channel, and an invalid-curve hole found during the work was fixed. The whole stack is pure Kern over the unsafe systems tier, no new C, TCB unchanged. Alongside it, sys.bluetooth gained a real RFCOMM implementation and sys.wifi stopped being a stub, which together retire the last stubs in the standard library.
The standard library grew from 303 modules to 354, and from 2,219 public functions to 2,982, in three deliberate directions. Forward-looking crypto and identity: ML-KEM-768 and ML-KEM-1024 (FIPS 203, up to Security Level 5) for post-quantum key encapsulation, mTLS with SPIFFE workload identity, a CBOR codec, OpenTelemetry across all three signals, and SLSA build provenance. The SPIFFE claim is stated precisely: svid_verify checks X.509-SVID fields (expiry, issuer, format), and signature and chain verification stay with the caller against the trust bundle. A WebAuthn module landed in the same wave and is covered separately below, because an audit of it is the more instructive story. A gap analysis against Go 1.25 produced seven modules where Kern was behind: std.context for request-scoped cancellation, deadlines and value propagation; std.unique for handle-based string interning; std.synctest with a fake clock and virtual time for deterministic concurrency tests; std.fips for FIPS 140-3 algorithm, key and TLS policy checking; net.csrf using Fetch Metadata rather than tokens; and data.json_stream for token-by-token and NDJSON processing. Both the CSRF and FIPS modules bridge into the SIEM event pipeline with CWE-117 log sanitization, so a policy violation is an alert, not a log line someone might read. Domain work landed too: DSP, geospatial, acoustic and DAS fiber-monitoring modules, a PDF writer with images, text metrics and alignment, and MIME multipart attachments for mail. Those arrived with adversarial tests that immediately found two real bugs of their own, an ifft that mutated its input and a swapped polynomial in the WGS84 to RD projection, both fixed.
Test coverage was being measured the flattering way. A new by-name measurement over the standard library asked a blunter question, which functions does no test ever reach, and answered 710 public functions. Working through that list in batches did what a coverage number never does on its own: it found code that had never worked. std.graph had never compiled. So had std.integrity, a documented security module that was, in practice, dead code. All four of a decoder family failed open on malformed input, as did jwt_payload and base64url_decode, which is the worst possible direction for an auth primitive. pg_ping, pg_is_connected and check_db reported the inverse of reality, so a health check called a dead database healthy. List == List was always true and read out of bounds while doing it (now E0318). Builtin dispatch hijacked any stdlib function whose name happened to match a C symbol. A private stdlib function poisoned that name everywhere it appeared. The test harness itself reported a perfect PASS when handed a non-executable compiler. Each is now fixed and pinned, and the tooling learned from it: W0002 warns on an import that names nothing the module exports, with a location, and the resolver's module-name guard stopped rejecting 27 legitimate files. This is the unglamorous half of a trust claim, and the register is kept in public: coverage is reported as two axes with the remaining gaps recorded as open validations, not gated exclusions.
A sustained hardening wave gave the runtime a ceiling wherever a remote peer chooses the cost. HTTP gained a total request deadline and a connection admission cap; JSON parsing caps nesting depth, which was a remote unauthenticated stack overflow; chunked decoding is linear rather than quadratic; Redis replies, OCI registry bodies and HTTP/2 bodies are all bounded; a Content-Length remote abort and a Zip Slip arbitrary write are closed; a TLS file-descriptor use-after-free is refcounted; a 32-bit size wrap in gRPC decode is fixed; three TLS WANT_READ busy-spins and a blocking connect inside the global pool mutex are gone; and the SSRF and egress allowlist now applies at every dialer rather than one. A separate pass drew on twenty CVEs from 2024 to 2026 plus the CWE Top 25 and added net.request_guard for per-request body, URI, header and query-parameter bounds, a per-key rate limiter with fail-closed overflow, and a path sanitizer that rejects URL-encoded traversal (%2e, %2f, %5c, %00) rather than only literal ... Two detector gaps were found and closed on a later sweep: csrf_origin_check used a substring test, so https://example.com.attacker.net passed the same-origin fallback, and the SSRF guard only recognised dotted-decimal IPv4, so 0177.0.0.1, 2130706433, 0x7f000001 and 127.1 all walked past a 127. prefix check; both now normalise and match exactly. The most consequential finding was not an exploit. An adopter audit found that std.compliance was twenty functions of pure string formatting with zero persistence: calling audit_entry() made a GDPR obligation feel discharged while the string vanished if you dropped it. It is now backed by the same tamper-evident chain the AI Act log uses, keyed-HMAC-SHA256-linked, fsync'd and append-only, with compliance_audit_verify returning true only if every record still links, which is the operator-verifiable proof a DORA Art. 17 or NIS2 Art. 23 examiner asks for. Editing one field in a written record breaks the chain and verification catches it. The rest of the compliance surface was audited and confirmed genuine, and audit_entry survives as an explicitly labelled formatter that persists nothing.
The July trust push turned the “real but manually verified” caveats into blocking CI jobs. reproducibility rebuilds the compiler and checks the IR and the binary byte-for-byte per commit; ddc compiles the compiler with two independent C toolchains and fails the build on any divergence, which is the Trusting-Trust check made routine. The independent seed path produces a working compiler without the shipped binary. Formal work extended past the proof-of-method: formal/caps/ proves well_typed_confinement, that a well-typed program which mints no kind-k capability can never reach an authority-k primitive, which is exactly the E0404 guarantee, plus that the functional checker matches the declarative typing relation. Supply chain: lockfile chain-integrity is a fail-closed SHA-256 chain, and kern-pkg now derives a dependency's actual capability set from kern audit-caps --json and rejects a package that escalates beyond its declared manifest. docs/VERIFICATION-DOSSIER.md ties every trust claim to the exact command that checks it, and scripts/kern_verified.sh grants the mark only to a toolchain that passes deterministic IR + reproducible binary + DDC + full conformance on the clean-room seed. Documentation joined the gate set too: make check-docs fails on any stdlib or test count that drifts from the source, and every fenced Kern example in the normative docs must typecheck (it found six real API-stale examples on first run and 18 stale numbers).
Secret is now a first-class compile-time taint tag alongside PersonalData<T> (E0302) and Untrusted<T> (E0303): a secret reaching any sink that does not declare a Secret parameter, a log line, print, a string concat into a DSN, is E0316. Comparing a secret with == is E0317, because byte-by-byte equality short-circuits and leaks how many leading bytes matched (CWE-208); the fix is secret_equals or secure_compare, which always inspect every byte. A whole-program pass now builds the call graph from every spawn/spawn_thread and rejects a scalar or struct module global written from a thread-reachable function as E0309, a compile-time data race. Integer +/-/* are overflow-checked by default (CWE-190): the compiler lowers them to LLVM overflow intrinsics and traps with the operands named; code that wants modular arithmetic says so with wrapping_add. The security review also closed two escapes: the raw __syscall intrinsic, which let a zero-capability program do arbitrary I/O, is now gated on Cap<Unsafe>; and a taint launder via tuple projection is closed in the typechecker. Both are macOS-verified and pinned by negative tests.
The data-confidentiality track is complete: all five network transports now do TLS. A reusable TLS client underlies SMTP (TLS and STARTTLS), NATS honours tls_required, Redis speaks rediss://, MQTT on 8883, and gRPC over grpcs:// with ALPN h2 was the last plaintext transport to close. One shared policy is applied at every mbedTLS config site, server and client: a TLS 1.2/1.3 floor that is asserted rather than inherited, and an explicit ECDHE-AEAD-only ciphersuite pin, so static RSA, RC4, 3DES and CBC-SHA1 are dropped by omission and forward secrecy is guaranteed. The Linux release binary is now built inside a pinned Debian trixie image against mbedTLS 3.x, so it negotiates TLS 1.3, and the TLS 1.2 configuration is recorded against the Dutch government's Forum Standaardisatie / NCSC guidance. Mail is reachable from Kern for the first time: net_smtp_send_mail is cap-gated on Cap<Net>, fails closed on a non-TLS channel, CR/LF-guards every address, dot-stuffs the payload, and batches many messages over one authenticated connection, with egress control and SIEM security monitoring on the mail path. net.siem_sink ships each SecurityEvent the moment it happens: CEF over syslog/UDP for ArcSight, QRadar, Splunk and Wazuh, or JSON over HTTPS for Splunk HEC, Elastic and Sentinel, fire-and-forget with no in-memory retention. Fleet-driven fixes landed alongside: the Postgres pool self-heals after a server restart, net.health readiness aggregation names which dependency is down, kctl gives daemonless day-2 container ops (ls, logs, exec, stats), and a communication-protocol security audit (about 75 findings across SSH, TLS, HTTP, WebSocket, messaging, DB and DNS) is landing in batches, each box-verified against real servers: the P0 stack buffer overflow in the MQTT packet builders (CWE-787); SSH host-key verification that fails closed on a changed key and refuses unknown hosts unless KERN_SSH_TOFU=1, plus a bounded connect timeout and keepalive floor under every TCP client; a Postgres sslmode look-alike-host bypass closed with exact loopback matching and verify-full when a CA root is configured, and savepoint names validated against SQL injection; a shared CR/LF field guard that stops NATS subject frame injection, an opt-in SSRF and DNS-rebinding guard screening the resolved address at every TCP connect (cloud-metadata and link-local first, strict adds RFC1918, CGNAT and ULA), WebSocket Origin and frame-length guards, HTTP request-line CR/LF rejection, NTP anti-spoofing, real HMAC sessions with constant-time verify, credential auth for NATS/MQTT/Redis that fails closed over TLS, and certificate pinning (KERN_TLS_PINS, SHA-256 of the peer DER, checked in the one shared handshake so every mbedTLS transport gets it). The remaining P2/P3 list is cleared and box-verified; the one item briefly recorded as open (MQTT-over-TLS receive) was root-caused to a buggy verification test and is marked fixed, which is how the register works: findings are named, not hidden, and corrected when wrong.
Five independent audits of the language itself were folded into one ranked register (docs/design/language-security-hardening-2026-08.md), which first records what holds up (the per-commit Trusting-Trust chain, the Coq-checked E0404 confinement, container isolation that exceeds a default Docker profile, complete overflow checking) and then the holes in the flagship claims, traced to four root causes and fixed at that level rather than per symptom. Containment: the seccomp seal denied socket/openat/execve by syscall number, but an io_uring ring could issue the same operations without the syscall entry; io_uring_setup/enter/register are now denied unconditionally under the seal and in containers. Cap<Net> egress narrowing was advisory; KERN_NET_ALLOW is now enforced at the C connect leaf, so even an RCE is bounded. Forwarder revocation was decorative (no use path); forwarder_use_* now fails closed, the alive flag is atomic, and a new compile error E0406 forbids an extracted capability from escaping its frame (return, field store, module global, spawn capture), so revocation gates the lifetime, not just the extraction event. Taint: enforcement was per-site code that each forgot a different tag; it is now one env-aware predicate routed through every boundary, string interpolation parts included, and it recurses into struct and union fields, so serialising a struct with a PersonalData field to a log or a DB row no longer launders the tag. Codegen: integer / and % trap on a zero divisor and INT64_MIN / -1 instead of LLVM undefined behaviour. Stdlib: fallible crypto returns Result<str> rather than an in-band "ERROR:" string or an empty key, Untrusted discharges only into structured sinks (argv, params, auto-escaped templates) with the string escapers gone, CSV cells are quoted against formula injection, and the audit and revocation-feed chains are keyed to the box anchor. Trust: a seed-faithfulness CI gate re-derives the seed IR with kern_v4 and byte-compares it to the manifest, stated honestly as trusting kern_v4 (a consistently poisoned seed pair would still pass; that is what the independent bootstrap and DDC gates are for). Every fix is box-verified and pinned by a negative test; the register keeps the honest T-model status alongside: flow soundness remains test-backed rather than machine-checked, and the external audit is a business decision not yet taken.
Every Kern binary now seals itself, before user code runs, to a seccomp-BPF filter that permits only the syscalls its capability set grants, and that set is derived by the compiler from the program's own types. A program that never mints Cap<Net> gets a kernel that denies socket(); one that never mints Cap<Process> cannot execve. E0404 already made ambient authority a compile error; the sandbox makes the same guarantee kernel-enforced at runtime, so a later RCE cannot exceed what the type system permitted. Nothing to configure, installed with NO_NEW_PRIVS so a spawned process inherits the filter. Self-hosting survives the seal: the compiler seals itself to FS|PROCESS and still bootstraps the next generation, running clang under the inherited filter. Landlock completes the filesystem story: the seccomp gate decides whether a program may open files, KERN_SANDBOX_FS_RO/RW decide which paths, layered on the seal and a clean no-op on kernels without Landlock.
A Kern service's identity on the network is now the SHA-256 of its own reproducible binary: kern_attest_self_hash() measures the running executable, so peers recognise a service by a hash they can rebuild themselves, with no certificate authority. Ed25519-signed challenges prove liveness, capability tokens carry what a caller may ask, the compiler injects a per-call guard on RPC serve, and the server attests back in an X-Kern-Server-Attest header. The mesh is bidirectional: the token proves who is calling and what they may ask, the attestation proves which build is answering. Unset config means disabled, fully backward compatible. Forensic record-replay welds nondeterminism to the audit chain: KERN_RECORD captures every clock read and random draw to a SHA-256-chained trace, KERN_REPLAY re-executes the incident run with byte-identical inputs, and kern_replay_verify() detects a trace edited after the fact. Built for DORA/NIS2 incident reconstruction, and a debugging tool for the heisenbug class.
The container engine's full mode (host bridge, veth pairs, NAT, inter-container networking) now runs for a non-root launcher: install-caps.sh grants cap_net_admin,cap_sys_admin to the binary once, the Docker-daemon privilege model but daemonless, and every later run by any user gets full networking. True-rootless mode adds inbound port publishing, AppArmor userns profiles and cgroup delegation (box-validated on cgroups v2), and compose service DNS resolves container names in capability and rootless mode. On the TLS side, kern ships an ACME v2 client (net.acme) that generates the PKCS#10 CSR and drives the Let's Encrypt exchange, and serve_tls_managed(server, cert_path, key_path) serves HTTPS from the resulting files, with reload_tls_cert to pick up a renewal without dropping the listener. HTTPS without a reverse proxy in front of it; the renewal loop is yours to schedule.
http_static(prefix, dir) now actually serves files, over both plain HTTP and HTTPS (it was a no-op that recorded the mount but never read it). Content type is set by extension, index.html is served for directories, requests are GET/HEAD only, and a strict path-traversal guard rejects any .. with a 403 before a file is ever opened (verified it will not serve /etc/passwd); the TLS path was refactored around a write sink so the same implementation serves plaintext and TLS sockets correctly. persist(s) is the epoch-GC escape hatch: under request-scoped GC (KERN_HTTP_EPOCH_GC) every object allocated during an HTTP request is reclaimed at request end, so a request-derived key stored into a long-lived global map (a rate-limiter's client-IP table, a cache) would dangle; persist copies the bytes onto the permanent heap so they survive, implemented as a thread-local allocator redirect that leaves epoch and collection semantics untouched.
Two adopter-requested tools turn claims into checks. A one-line .kern-version file pins the toolchain: kern build / run / check compare it to the running compiler and print warning: kern-version-mismatch when a compiler upgrade or a stale binary drifts from what the project expects (warning-only, so it never breaks a build; CI that wants hard enforcement greps for the line). kern audit-docker <file> walks a program's full resolved import graph and reports whether it takes any Docker dependency (an import of sys.docker, which shells out to the docker CLI, or a /var/run/docker.sock reference): a clean program prints audit-docker: PASS, a Docker dependency is FLAGGED and the command exits non-zero so CI can gate on it. “Docker-free” becomes auditable: a Kern binary is native and links no Docker client.
The OWASP injection family is eliminated at the level of the grammar, not patched at runtime. Five @<kind>_literal annotations (@sql_literal, @shell_literal, @url_literal, @regex_literal, @template_literal) require the decorated argument to be a string literal at every call site, so a query or command built from user input does not type-check. A Url<Trusted, Untrusted> type-state closes SSRF for URLs built at runtime: parse_url yields Url<Untrusted>, and only trust_url(raw, allowed_hosts) promotes it after a host-allowlist check. @url_literal also rejects any literal that does not start with https://. The promise is concrete: an AST shape an attacker would need to land the bug does not exist in valid Kern source.
Injection prevention stops a query built from user input from type-checking. The typechecker now goes one step further and validates the SQL itself against your declared schema, before the program runs. A query against a table that does not exist, or a SELECT / INSERT naming a column that is not in that table, is a compile error (E0311) — not a 500 in production at 2am. The whole class of “typo in a column name” and “migration drifted from the code” bugs moves from runtime to kern build. Combined with the @sql_literal rule, a Kern SQL statement is checked for both injection safety and schema correctness at the same compile step.
The container subsystem used to shell out to a host Docker or Podman. It is now a complete OCI engine compiled into the language. It pulls and runs real images (debian:bookworm-slim, alpine:3.19) with nothing on the host but the Kern binary, a Linux kernel 5.15 or newer, and libc. No docker, podman, runc, crun, skopeo, iptables, nft or iproute2 required. HTTPS and tar extraction run in-tree (vendored mbedTLS plus a statically linked libarchive). Network setup is hand-rolled netlink (RTM_NEWLINK / NEWADDR / NEWROUTE), and outbound NAT installs an inet kern_nat nftables table directly over NFNETLINK_NFT. oci_pull_image_verified() checks a cosign-compatible Ed25519 signature and pins the manifest digest. A build gate (make check-container-no-shellout) fails if popen or system appears in the container runtime sources, and a CI leg apt-purges every shellout binary before running the suite under an strace execve tripwire.
The container engine now extends beyond Linux namespaces. On macOS, Kern boots a full Linux kernel via Apple's Virtualization.framework — ARM64 with GIC emulation, virtiofs file sharing, and virtio-console. Multi-container lifecycle works on macOS: cgroups v2, NAT networking, log capture, and port forwarding, all running inside the VM. On Linux, containers run directly via namespaces as before. Production deploys still need only the Kern binary + Linux kernel 5.15+ + libc, but development on macOS now runs real Linux containers without Docker Desktop.
All authority-bearing entry points — network, filesystem, process, FFI, environment access — now require explicit Cap<T> capabilities. Only the entry module can mint root capabilities; every other module must receive them as arguments. Compile error E0404 enforces this unconditionally. The entire conformance suite threads capabilities. Combined with the five @literal injection rules, kern's security model covers both ambient authority and injection attacks at compile time — two of the three classic attack surfaces (the third, memory safety, is mitigated by the GC and stack guards).
Generics (v0.7): selective monomorphization for stdlib hot paths — List<T>, Map<K,V>, Result<T>, Option<T>, Decimal — emitted as linkonce_odr typed wrappers so multiple compilation units share them without link conflicts; @monomorphize opt-in for user code; type-erased fallback. Async (v0.8): real spawn/await codegen, cooperative kern routines (16 KB guard-paged stack, configurable via KERN_ROUTINE_STACK_SIZE), routine-aware libuv IO (file/DNS/TCP), routine-aware libpq + mbedTLS, spawn_thread for CPU-bound work via the libuv worker pool. Two spawned sleep_ms(80) tasks complete in ≈82 ms. ABI-breaking decisions are now behind us, not ahead.
kern-pkg ported to Kern (full surface): init / build / run / test / add / remove / verify / install / publish / search / update with manifest [dependencies] / [dev-dependencies] parsing. The Python shim is gone. EU-sovereign cloud KMS providers: KERN_KMS_PROVIDER routes kms_encrypt / kms_decrypt to Scaleway (EU-native), Azure Key Vault (with AAD bearer cache), or an OVH stub; local AES-256-GCM remains the default. Chain-hashed AI audit log: every record carries prev_hash + record_hash (SHA-256 over the previous hash plus canonical body); kern_ai_audit_verify() replays the file and refuses appends if any link mismatches, and the kern ai-audit verify CLI runs that replay from the shell. This closes the EU AI Act traceability gate.