Skip to content
The moat

The kernel decides what runs. Not the prompt.

Inner Warden's Execution Gate is a kernel-enforced exec allowlist: an eBPF LSM hook denies any binary that wasn't pre-authorized, at exec time, with -EPERM. Because it lives in the kernel, a compromised userspace agent can't route around it. Below is real evidence from the lab.

Honest scope: this is a controlled lab result, founder-run, on a single host (test001, Ubuntu kernel 6.8). It is the kernel-backstop layer (L2) demonstrated end-to-end, not a claim of external customers or fleet-scale deployment. The gate ships inert in the open-source sensor; arming is the paid Active Defence step.

Kernel, not prompt

Enforcement is an eBPF LSM hook on bprm_check_security. It runs in the kernel on every exec, independent of the agent process. The differentiator vs cooperative-hook EDRs.

Agent-can't-bypass

If an attacker hijacks the userspace agent, they still cannot execute a binary the kernel gate hasn't pre-authorized. The decision is below the thing they compromised.

Fails safe

Ships INERT by default (nothing changes for free users). Arming is gated on a zero-deny rehearsal. Disarm needs no license and works in-process even while armed, the valve always opens.

Watch it happen

The gate, armed and blocking, in one unedited take

A real terminal recording on the lab host: a zero-deny rehearsal, arming the gate in enforce, an allowlisted binary running normally, an unknown binary denied at exec by the kernel, then a clean disarm. Nothing is mocked or sped up beyond trimming idle pauses.

test001 · kernel 6.8 · x86_64 · Execution Gate (eBPF LSM)
starting recording…
loading…raw .cast

The recording plays on its own; use Replay to watch it again. The annotated breakdown of the two key moments is below.

  1. 01
    The catch

    The kernel refuses an unknown binary

    With the gate armed, an executable that is not in the pre-authorized allowlist is denied at exec time by the eBPF LSM hook (bprm_check_security) with -EPERM, before a single instruction of it runs. Legitimate binaries keep working. This is enforcement the agent process cannot route around: a hijacked agent cannot un-deny what the kernel denied.

    test001 · kernel 6.8 · gate ARMED (LSM_POLICY key 3 = 1)
    $ /bin/echo hello # allowlisted
    hello
    $ /tmp/unknown_test # NOT in the allowlist
    bash: /tmp/unknown_test: Operation not permitted
    RESULT=UNKNOWN_BLOCKED_by_gate_EPERM
    # operator approves it → live map updated in-process → re-exec passes
    RESULT2=TARGET_AUTO_HEALED_now_runs
    $ exec-gate disarm --apply # safety valve, no license needed
    disarm_in_process_key3 = 00 00 00 00 (services restored active/active, zero brick)

    Unknown binary blocked at the kernel; known binaries unaffected; approve → auto-heal; disarm always works. No brick.

  2. 02
    The safety net

    It refuses to brick itself

    Arming a kernel exec-gate is dangerous: miss one path a live process needs and you lock the box out. So arming is gated on a pre-arm rehearsal that mutates nothing, it checks every boot-essential and every currently-running process against the set the gate would enforce, and refuses to arm if anything legitimate would be denied. On its very first real run it caught ten paths the naive scan had missed (systemd service helpers, the /bin/sh symlink, a binary reachable by two names) and refused. We fixed the coverage; the same rehearsal now passes clean, and that clean pass is the precondition for arming.

    test001 · kernel 6.8 · gate DISARMED (dry-run, mutates nothing)
    # first run, caught real brick-risks and refused:
    $ exec-gate rehearse
    ✗ 10 path(s) WOULD BE DENIED, DO NOT arm (systemd helpers, /bin/sh, …)
     
    # after coverage fixes, same check, now clean:
    $ exec-gate rehearse
    rehearsal: 35 candidate exec path(s) checked against 3036 enforced path-hash(es)
    ✓ zero-deny, every boot-essential and currently-running binary is covered. SAFE to arm.

    The gate that would brick the host never gets armed. A clean zero-deny rehearsal is the precondition; rehearsal first, enforcement second.

A second layer

DNS Guard: known-bad domains never resolve

The same shape applied to the network. DNS Guard is a local sinkhole resolver: in enforce, any domain on the threat-feed denylist (tens of thousands of IOC, C2, and DNS-tunneling domains) is answered with NXDOMAIN, so malware callbacks and exfiltration-by-DNS fail at resolution. Clean domains are untouched. Like the Execution Gate it ships in observe, enforce is the paid step, and disarm needs no license. Below is a real recording: a denylisted domain resolving in observe, blocked in enforce, and resolving again after disarm, with a clean domain unaffected throughout.

test001 · DNS Guard sinkhole · 127.0.0.1:8553 → upstream
starting recording…
loading…raw .cast
Zero-trust for the agent

The gate, scoped to just the AI agent

A host-wide allowlist fits a locked-down appliance, but a general server constantly runs new legitimate binaries (package updates, cert renewals, containers). So the gate can be scoped to a single cgroup: the AI agent's. Then the kernel allows only pre-authorized binaries inside the agent's process tree and leaves the rest of the machine untouched. Below: a real OpenClaw agent on the lab host, scoped and armed. The same unknown binary runs on the host but is denied at exec inside the agent's cgroup, and an allowlisted binary still runs there. A hijacked agent can only execute what was pre-authorized, enforced below userspace, with no collateral on the host.

test001 · kernel 6.8 · Execution Gate scoped to the OpenClaw agent cgroup
starting recording…
loading…raw .cast
Multi-tenant fleets

One rogue agent in a shared fleet, named and contained at the pod

Production AI-agent fleets run many agents in containers on one node. The question stops being “did something happen on this host” and becomes “which tenant and which pod did it”. In this unedited take on a real cloud kernel, two tenants share a Kubernetes node and one agent pod goes rogue. InnerWarden reads the pod identity straight from the kernel cgroup (the agent cannot spoof it), attributes every incident to the exact tenant and pod while the benign tenant stays at zero, then arms the Execution Gate scoped to only that pod: a new unknown binary is denied at exec in the kernel, while the pod's allowlisted binaries, the other tenant, and the host all run untouched.

Azure · kernel 7.0 · k3s · per-tenant attribution + agent-scoped Execution Gate
starting recording…
loading…raw .cast

detect → attribute (exact tenant and pod) → contain (per-pod, in the kernel). The host and every other tenant are never gated.

See the primitive yourself

The gate primitive (the EXEC_ALLOWLIST map and the bprm_check_security hook) ships in the open-source sensor, inert and auditable. Install it and inspect the loaded eBPF programs, the kernel-level enforcement is there to read, not a black box.

curl -fsSL https://www.innerwarden.com/install | sudo bash