Safe Observe and Allowlist
The never-blind workflow for tuning InnerWarden to a host: stay in observe, learn a baseline, verify each candidate, then arm enforcement gradually.
Safe Observe and Allowlist
For: operators (and AI agents acting for them) adapting InnerWarden to a specific machine, so it stops flagging what is genuinely normal, without handing an attacker a permanent free pass.
This is the page that keeps you out of trouble. Read it before you trust anything or arm enforcement. The agent-facing version of this same workflow ships on every box at /etc/innerwarden/AGENTS.md.
The trap, stated plainly
People will say, reasonably, "allowlist what is normal on this server so it stops alerting on it." The dangerous reading of that is "allowlist everything currently running." Do not do that.
The reason is simple and it is the whole point of running InnerWarden: malware on the box is "currently running" too. A miner, a reverse shell, an attacker's cron job, are all "normal" by the lazy definition of "it is here right now." If you allowlist by presence, you blind the tool to exactly the thing you installed it to catch, and you do it permanently. Blind-allowlisting is the single most damaging mistake you can make here.
So InnerWarden is built to never trust blindly. The safe workflow below goes through five gates, in order, and the product enforces some of them for you. Skipping ahead is what gets people compromised.
One command, then read what it says
innerwarden-ctl arm is the whole sequence in one command. It surveys the host,
repairs the preconditions it owns, pairs the AI agent, and turns on every control
this machine can actually run — observe first, with a rehearsal in between.
sudo innerwarden-ctl arm --check # survey and print the plan, change nothing
sudo innerwarden-ctl arm # do it
Run --check first. It prints three lists, and the third is the one worth
reading: what it will NOT turn on, why, and the command that changes that. A
control that cannot enforce on this kernel is reported as blocked rather than
armed, because a guard that loads but can never deny is worse than an absent
one — it looks like protection.
The kernel guards need bpf in the LSM stack
The Execution Gate, the Secret Read Guard and the userns guard are kernel LSM
hooks. Most stock cloud images (Ubuntu on Azure, AWS and GCP among them) do not
include bpf in their active LSM list, and without it those hooks load and can
never deny.
The installer detects this and adds bpf to the kernel command line for you,
preserving whatever list the host was already running. It requires a reboot
and never performs one: when to restart a host is your decision. Check where you
stand with:
cat /sys/kernel/security/lsm
bpf in that list means the kernel guards can enforce. Absent, and
innerwarden-ctl arm will say so and refuse to claim otherwise.
The never-blind workflow
1. Stay in observe / dry-run
A fresh install already starts here: it watches and explains, it does not block or kill. Nothing is being suppressed and nothing is being enforced, everything is logged. Confirm you are in this posture before doing anything else (the dry-run state is the responder setting; see Configuration for the key and CLI Reference for the command). This is your safe place to learn from.
2. Let the baseline learn
InnerWarden learns this host's normal over a window before it trusts anything: the event rate per hour by source, which process spawns which child, when users normally log in, where processes normally connect out. You do not configure "normal," it is observed. Check how far along that learning is with innerwarden get posture. Do not arm enforcement until there is a real baseline, an empty baseline trusts nothing and over-reacts to everything.
3. Review what is actually firing, do not guess
Look at the real activity before you decide anything is benign:
innerwarden get incidents --days 7
innerwarden get decisions --days 7
You are looking for the handful of things that fire repeatedly and that you can explain. An alert you cannot account for is a candidate for investigation, not for the allowlist.
4. Verify every candidate before you trust it
For each IP, user, or process you are tempted to allowlist, confirm it is genuinely benign. Do not take its presence as proof.
- Cross-check reputation:
innerwarden get entity <ip>, and the loopbackcheck-ipfrom Connect Your Agent. - Confirm a flagged process is an expected service with a known parent, not something masquerading.
- Ask a human to confirm anything ambiguous. An unexplained long-running process, or an outbound connection you cannot account for, is precisely what you must not wave through.
This is the gate attackers count on you skipping.
5. Propose, never silently apply, then arm gradually
Show the human the exact list you intend to trust and why. Add only what they confirm. The trust commands are owned by CLI Reference; the shape is:
innerwarden trust add --ip <addr> --reason "<why this is known-good>"
innerwarden trust list
innerwarden trust suppress <pattern>
One thing that surprises people, and is deliberate: trust means monitor-only. A trusted entity is still detected, still logged, still notified. Only the automatic block is held back. You keep full visibility even on things you trust, so if a "trusted" service starts behaving like an attacker you still see it. Trust suppresses the trigger, never the truth.
Only after a clean baseline and a human-confirmed trust list do you arm enforcement, and even then, gradually. Leave dry-run on first, watch the decisions it would have made, and remove dry-run only once you trust those decisions. The responder enable / dry-run controls live in CLI Reference and the underlying key in Configuration.
The safety floor the product enforces for you
You do not have to remember all of this perfectly, because InnerWarden holds a hard line in code:
- The skill_gate proof floor. Before any block (or any decision that would suppress a block) executes, it is validated against your configuration. An allowlist-driven attempt to bypass a block without a valid proof cannot get through. Even a maliciously crafted AI response, a buggy detector, or a compromised upstream library cannot route around your policy without changing the gate's code, which would require a code review. The contract is documented in Trust and Safety Invariants. Do not try to work around it, it is there to protect you from your own automation.
- Detection is never suppressed at detect time. False-positive handling happens in layers after detection (organised defaults, then the learned baseline, then AI triage, then your decision), never by switching a detector off at the source. Specific high-confidence signals stay always-on; only generic heuristics are ever relaxed.
The hard rules, restated: you are forbidden from auto-allowlisting a process, IP, or path just because it is present, and from arming enforcement before a clean baseline plus a human-confirmed trust list.
The stronger guarantee: Execution Gate rehearsal (Enterprise, Active Defence)
If you want pre-authorized-execution hardening, the Execution Gate adds a kernel allowlist for binaries. It is part of Enterprise (the paid Linux host stack, under Active Defence), built around the same never-blind principle, and gives you proof before you arm:
- an observe mode that logs what would be denied and blocks nothing, and
- a rehearsal that runs over a window and proves zero legitimate denials before you ever switch it to enforce.
That is the same discipline as the workflow above, made into a feature: measure the blast radius, prove it is empty, then arm. An honesty monitor also raises an alert if a signed allowlist is ever staged but not actually applied in the kernel, so the gate can never silently go inert. Everything on this page, the host detection, the baseline, the audit trail, and the Execution Gate, is Enterprise. The free Community piece is the innerwarden guardrail that screens an agent's commands and MCP calls, described in AI Agent Guardrail.
Hard rules and your rules
There are two kinds of rule in the Execution Gate, and it is worth being able to tell them apart at a glance, because one kind you never touch and the other kind is yours.
Hard rules ship with the product. They are the same on every machine and there is no setting for them, on purpose:
- the gate only ever guards an agent's own process tree, never the whole host;
- a binary in a writable or hidden place (
/tmp,/home, a dotfile) is always held for you; - a shell or a privilege tool (
sh,bash,sudo,su,pkexec, and friends) is always held for you, whatever directory it lives in, because an agent suddenly running one of those is the exact thing this gate exists to show you; - an allowlist file that cannot be read never becomes "allow nothing";
disarmnever asks for a licence.
Your rules describe your machine. Each one is a single line, written once, and nothing about your machine has to be known by InnerWarden beforehand:
| the rule | how you set it |
|---|---|
| which process is guarded | innerwarden-ctl agent connect --unit my-agent.service, which writes one pre-start line into that unit so the guards scope to it on every start, restarts and reboots included |
| what it may run | the allowlist, one entry per binary, each stamped with where it came from: the baseline scan, you, or an automatic approval |
| a path that may always run | an allow_exec rule, for tools that update in place (/usr/bin/git is the same tool after an upgrade; a path rule says so) |
| how eager automatic approval is | one word on the loop: conservative (the default), off, or learning |
It tried, it was denied, do you want that to be a rule?
That is the whole loop, and it happens in your Telegram. When the gate holds a binary, you get a message with what ran, where from, and three buttons:
- Allow this binary: this exact build may run. A rebuilt binary asks again, which is the point of a content hash.
- Always allow this path: the path may run whatever its content, so upgrades keep working. This button is withheld for
/tmpand the like, where a path is not an identity. - Reject: it stays denied and nobody asks you again.
Whichever you press is written into the allowlist with your name on it, and the kernel follows within seconds. Nothing to configure for any of this; if Telegram is set up for your alerts, it is set up for this.
The tap answers you, in the chat. The buttons leave the message the moment you press one (no second tap on a decided thing), a reply under it says which button and by whom, and once the kernel has it the gate replies again under the same message with what changed, that it is applied, and an Undo button. Undo puts that answer back on hold: the next attempt asks you again. It only ever narrows, never opens anything, and it will not touch an entry that a seed or the CLI made rather than a button.
The automatic approver never decides for you on the cases that matter: shells, privilege tools and staging paths always reach you as a question. And the first time the loop starts it listens from that moment; it does not go back through history and approve things nobody was asked about.
Where this connects
- The agent guardrail layers that this workflow protects: AI Agent Guardrail
- Wiring an agent that should consult InnerWarden before acting: Connect Your Agent
- The contract for what autonomous response will and will not do: Trust and Safety Invariants
- The exact commands and flags: CLI Reference and the config keys: Configuration
- What gets detected in the first place: What It Detects