grithdocs

The quarantine digest

Why grith routes ambiguous calls to a human review queue instead of guessing.

The digest is grith's queue for calls that scored ambiguously. Auto-allow is for calls that are obviously fine. Auto-deny is for calls that are obviously not. The digest is for everything else — and "everything else" is where most of the actual security decisions get made.

The shape of the problem

If you could write a function is_this_safe(call) → bool that was always right, grith wouldn't need a digest. You can't. Nobody can. Real agent workloads have:

  • Calls that are obviously safe (ls, cat README.md, git status). The filters handle these — auto-allow.
  • Calls that are obviously not (curl | sh from an unknown host, reading ~/.aws/credentials from a session that's about to network out, anything that trips canary detection). Auto-deny.
  • Calls that could be fine in this context but suspicious in another (cat ~/.ssh/config — fine if you asked the agent to fix a typo there, very not fine if you asked it to summarise a README). The filters can't know which context applies.

That last category is what the digest is for. Rather than guess, grith freezes the calling process and asks.

Process freezing

When a call lands in the queue, the calling thread is already held at its ptrace/seccomp syscall-stop — grith simply does not resume it, so the syscall is never committed. The thread sits there, paused, with the syscall args staged in registers. It cannot proceed, but it also cannot fail — it's just held. (Only the calling thread is held; the rest of the process tree keeps running.)

That matters because:

  • The agent doesn't see a permission error and decide to retry the call a different way. It just hangs.
  • The OS doesn't see a partial syscall and roll back state. The syscall has not started yet.
  • A human (or webhook) can take as long as they want to decide. Up to proxy.review_timeout_seconds (default 300s = 5min), after which grith auto-denies.

When a decision is made, the thread either runs the original syscall (approve) or returns it with EPERM / equivalent failure (deny).

What the reviewer sees

A digest item carries every piece of context the filters had plus a few they didn't:

  • The call itself: operation type, target, args, originating PID and command line.
  • The composite score and which threshold zone it crossed.
  • Per-filter contributions: each filter's emitted score and any annotations (matched patterns, denied paths, taint sources).
  • Session history: the last N calls in the same session, for behavioural context.
  • Reputation snapshot: what the trust table says about the destination today.
  • Profile: which supervisor profile is active, and which entries got exercised.

This is enough to make a yes/no decision in roughly the time it takes to read the filter list. If it isn't, something's off — usually that means the score is in the queue zone but the filters have nothing alarming to say. That's usually a threshold mis-tuning. See Tuning scoring thresholds.

The actions available

The reviewer can:

  • Approve — let this call run.
  • Approve + learn — let it run, and teach the reputation system that this shape is okay. Similar future calls will auto-allow.
  • Approve + unlock egress — for network calls. Allows this destination for the rest of the session.
  • Allow always (Pro) — adds the call to a permanent allowlist. Sparingly.
  • Deny — block this call; the syscall returns EPERM.
  • Deny + terminate — block + kill the process tree. For confirmed exfil.
  • Escalate (Pro) — route to a teammate or channel for second opinion.
  • Skip — leave it queued. Useful for "I'll come back to this".

Each decision is recorded in the audit log with the user who made it (in multi-user team setups) and the rationale annotations from the filters.

Why batching matters

In a session of any length, multiple calls will land in the digest. Most agents do roughly the same kinds of things, which means the digest items cluster: "this agent is reading config files all over my home dir." Reviewing them one by one is exhausting.

The CLI and dashboard both let you batch-decide on related items:

grith digest list --filter session=abc12345
grith digest approve --filter session=abc12345 --target '~/.config/grith/**'

Or in the dashboard: select a group, click approve. The reputation system records this as a batch approval, which is stronger evidence than the same approvals one at a time.

Channels (Pro)

A Pro license unlocks notification channels. The digest item gets posted to Slack / Discord / Telegram / Teams / email / PagerDuty / Opsgenie / a webhook. The reviewer clicks an approve button (or replies in a thread), and the decision flows back via an HMAC-signed callback. See Notification security model for the threat model around remote approvals.

When the queue is empty

A grith deployment with the queue mostly empty is normal — that's the goal. Most calls auto-allow because the filters cleared them or because reputation absorbed them. A queue that's never empty after a few weeks of use means either:

  1. The agent is genuinely doing wild stuff, and you should look at it more closely.
  2. The scoring thresholds are too tight; relax them via proxy.auto_allow_threshold.

A queue that's too empty under attack is the failure mode that matters more. That's what the canary and DLP filters guard against: they're hard gates, not contributors, so they will deny exfil regardless of whether anyone reads the digest.

See also

Last updated: 2026-05-14Edit this page on GitHub →