WhisperDocs
Endpoint

Containment: on-host response and the off-host kill-switch

Response happens in two layers. A bounded, opt-in tier acts on the host. The lethal lever lives off it, on our own infrastructure, so it holds even when the host is fully owned.

A host-only sensor runs its brain and its response inside the machine it watches. When an attacker or a rogue agent owns the host, the off-switch you were counting on is now under their control. Whisper Endpoint keeps a near lever for fast, reversible action when the host is still yours, and a far lever the host can never reach. The far lever is the one that matters at incident time.

In the seven-layer architecture this page is the top two layers: policy, the everyday governance expressed against the /128 from off the host, and response, the containment that fires when governance is not enough. They share one design: the identity is the handle, and the enforcement point is our network, not the host's software.

Two layers, and why

The default posture is observe-only: the sensor watches and reports, and it does not sit in the critical path. Response is something you add, deliberately, in two independent places.

Where the containment lever lives A host-only EDR keeps its response inside the host, so a compromised host takes the response with it. Whisper keeps the revoke lever on its own network, acting on the host's identity from outside. HOST-ONLY EDR compromised host brain + response kill command Own the box and the off-switch goes with it. WHISPER ENDPOINT compromised host sensor observes · /128 Whisper network op:revoke → identity gone PTR / AAAA DANE / egress cut The lever sits off the host. Owning the box does not reach it.
Where the lever lives is the whole argument. A host-only EDR loses its response with the host; the Whisper revoke acts on the host's identity from outside it.

The far side: the off-host kill-switch

Every host and agent carries a routable IPv6 /128 out of 2a04:2a01::/32 (announced by AS219419), named in DNSSEC-anchored reverse DNS and pinned in DANE. That identity is the handle. Revoking it stops two things at once: its resolution (it can no longer look names up through Whisper) and its egress (traffic sourced from its /128 is cut). The change propagates worldwide at DNS-TTL.

You trigger it from the CLI or the control plane, against the identity, not the host:

# the simple form
$ whisper kill --revoke 2a04:2a01:8dae:4521:45b8:b241:4f91:56e2
whisper: 2a04:2a01:8dae:4521:45b8:b241:4f91:56e2 - released

# the same act on the control plane (API key redacted; use a throwaway, never a live host)
$ curl -s -X POST https://graph.whisper.online/api/query \
    -H 'content-type: application/json' \
    -d '{"query":"CALL whisper.agents({op:\"revoke\", address:\"2a04:2a01:8dae:4521:45b8:b241:4f91:56e2\"})","apiKey":"whisper_live_...redacted"}'

You verify the teardown the same way you verified the identity: with stock tools, keyless, against the IANA root. A revoked or never-held /128 does not return an empty answer, it returns authenticated non-existence, DNSSEC-signed denial you can check for yourself:

$ dig +dnssec -x 2a04:2a01:dead:beef::1 @9.9.9.9
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 26376
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 8   # ad is the resolver's claim about the denial; delv re-derives it

;; AUTHORITY SECTION:
1.0.a.2.4.0.a.2.ip6.arpa. 300 IN SOA   ns1.whisper.online. hostmaster.whisper.online. 1787608004 ...
1.0.a.2.4.0.a.2.ip6.arpa. 300 IN RRSIG SOA 13 10 300 20260826210000 20260824200000 58485 ...
d8pbc0d1ermlg13osn18rbvi7e9la6i1.1.0.a.2.4.0.a.2.ip6.arpa. 300 IN NSEC3 1 0 0 - D8PJBQUAPIJCKDFBND55H0F75GLA64HG
i

Why it holds when the host is owned. The revoke does not ask the host to do anything. It changes what the network and the authoritative DNS will do for that identity. A fully-owned host cannot un-revoke itself, because the decision was never on the host. This is the move a host-only EDR structurally cannot make.

Containment is scoped, reversible, and leaves a durable audit trail: every contain action is written to the transparency ledger and exposed as a keyless third-party proof at /api/contain/action/<ledgerId>, so an auditor can confirm a containment happened without being handed any trust. Reversal is a scoped, deliberate act of its own. See Compliance evidence.

Agent trees: cut the parent, cut the branch

Agents nest. A machine that is a Whisper agent runs a browser agent that egresses through it, which spawns a scraper of its own, and each of those gets its own governed /128, to a depth of 32. The tree is measured, not claimed: the egress plane observes a child's connections physically arriving from its parent's /128 and records that edge, so "who is nested behind this identity right now" is ground truth, never a self-declared field an attacker could point at a victim. The details of the identity model are in The /128 identity; what matters here is what it does to containment.

Policy composes down the measured chain, most-restrictive-wins: a descendant's effective egress is its own rule-set intersected with every live ancestor's, so a deny at any layer binds everything transiting below it, and a parent can never widen what a child may do. Which yields the containment property this section is named for: kill the parent and every descendant behind it is cut on its next connection. You never chase the children individually.

A tenant root with two agent branches. A kill applied to one branch's parent severs that parent and all of its measured descendants, drawn dashed and struck; the sibling branch is untouched, zero collateral. ONE TENANT · EACH NODE ITS OWN /128 · EDGES = MEASURED TRANSIT workstation ...:41e2 · root of the tree build agent ...:8c11 · KILLED: op kill on this node deploy agent ...:2b07 · untouched, zero collateral browser sub-agent ...:f3aa · cut: next CONNECT deny scraper sub-agent ...:19c4 · cut: next CONNECT deny the walk, per CONNECT, in our egress plane: scraper ▸ its own rules: allow ▸ ancestor build agent: KILLED ▸ DENY bounded to 32 hops · fails closed past the bound · the refusal is uniform, so a probe learns nothing deploy agent ▸ no killed ancestor on its measured chain ▸ ALLOW
The kill cascade: one kill at the parent, and the egress walk denies every descendant behind it on its next connection. The sibling branch never notices. Edges are measured transit, so the tree cannot be forged by declaration.

Two levers cut a subtree, in escalating finality:

i

Why the cascade cannot be escaped. The enforcement walk follows only the measured chain, never a caller-declared parent pointer, so a hostile agent can neither hide behind a fake parent nor name a victim's identity as its parent to read that victim's policy state. Past the 32-hop depth bound the walk fails closed, and the refusal is uniform on every path, so probing the cascade leaks nothing about the tree.

Before the kill-switch: policy on the same handle

Revocation is the last resort. The everyday layer below it is a set of policy shapes, all expressed through the same one control verb (whisper.agents), all keyed by the agent's /128, and all enforced off the host, in our resolver and egress plane, so a compromised agent cannot disable its own rules the way it could flush its own iptables:

ShapeWhat it governsEnforcedStatus
Egress firewallPer-identity allow/deny rules on destination ip, cidr, host (exact or any-subdomain) or port; ordered, first match wins, then a default action. Every rule-set write lands on the same audit trail as a revoke.egress plane, once per connectlive
Process-trust graded egressMaps the graph's per-process trust tiers T0..T4 onto the freedom ladder none < dns-only < mediated < direct < unrestricted; the endpoint's worst observed process tier decides. Only a confirmed graph known-bad verdict reaches T0, never a fail-open guess.egress plane, per connectlive
Byte caps and budget killPer-identity byte, connection and request ceilings folded into the live meter, tightest cap wins; kill:true cuts live tunnels immediately.egress plane, live meterlive
Per-run scopeA windowed, deny-default destination allowlist bound to one run's duration: only the listed destinations are reachable while the window is open.egress planelive
Resolution geo policyCountry allow-lists and deny-lists evaluated live per resolution against the graph's view of where a name resolves; deny wins on conflict.the resolverlive
Jurisdiction-tagged allocationThe /128 itself allocated inside a country-tagged block, so the address encodes its jurisdiction, published in RDAP and an RFC 9092 geofeed.at allocationopt-in, off by default
Per-device policyThe same policy verb with a device selector routes rules to one identity instead of the tenant; a device override only ever escalates, never downgrades a graph-critical block. A revoke drops the override, so a recycled /128 never inherits one.the resolverlive

The trust ladder in one picture, since it is the shape that turns detection into graded restraint instead of a binary kill:

graph trust tier            egress freedom (decided per connect, off-host)
T4 verified          ──►  unrestricted
T3 neutral           ──►  direct
T2 unverified        ──►  mediated
T1 suspicious        ──►  dns-only      ◄─ refusal enforced live
T0 known-bad         ──►  none          ◄─ only a CONFIRMED graph verdict lands here
i

Maturity, per lever. The read-back of every policy write tells you whether that namespace is enforced or merely stored: the egress levers above answer enforcement=live; console namespaces that are recorded but not yet enforced answer enforcement=stored, and a stored token is never rendered as live policy. Jurisdiction-tagged allocation is opt-in and disabled by default; until you enable it, allocations are byte-identical to untagged ones, and a jurisdiction lookup can never block an allocation.

The near side: bounded on-host response

When the host is still yours, a complementary tier can act on it directly. It is armed and opt-in, never on by default: a host that opted into observe telemetry has not opted into acting. When you arm it, the actions are drawn from a fixed allowlist, run over a poll-only channel keyed to the host's own /128, and each one is audited.

ActionWhat it doesHow it is kept safe
process.stopStops a processpidfd_open + pidfd_send_signal, immune to PID reuse; a safe signal, never a blind SIGKILL mid-transaction
quarantine.fileDefangs a file in place to a quarantine storeThe file is neutered to mode 0000, the sha256 recorded so the move is verifiable and reversible
service.restartRestarts a unitAllowlist-only; no shell, no $PATH lookup, absolute program paths only
package.updatePatches a packageThe package manager transaction is left intact; a build guard fails compilation if a shell literal ever appears

An opt-in local-policy exec guard can also close the loop from observe to verdict to block on the host itself. And a reversible freeze, a SIGSTOP across the offending process tree that SIGCONT lifts, ships in observe-first mode: it detects and can hold, off by default and enforcement-gated, so nothing acts on your fleet until you say so.

i

Maturity. The on-host response tier and the reversible freeze are real and live-fire proven, but they are a complement, not the primary line of defense, precisely because they live on the host. Process-trust graded egress refusals (the none and dns-only rungs) are enforced live in the egress plane, and the write's read-back says so per lever. Ransomware copy-on-write rollback is designed and on the roadmap, not shipped. The adversary-proof lever remains the off-host revoke.

The containment rail, in the console

In the operator console, containment is a rail with a durable audit trail: arm, sever, a keyless proof of the sever, and a reversal path. Every step is recorded, and the proof is one anyone can re-check.

The Whisper EDR console containment rail showing the sequence arm, sever, proof and reversal for a contained host, with a severed count and a link to the keyless contain proof.
The out-of-band containment rail: arm, sever, a keyless proof of the action, and a reversal path, each step written to the ledger. Real capture, demo data.

The assets a host agent can never contain

Because the far lever is network-layer, it reaches things that will never run a kernel sensor:

Calm is the composure of power held in reserve. The sensor does not cry wolf, because the lethal lever is already outside the attacker's reach.