grithdocs

Session containment

Two different mechanisms share the name: a sticky session-lifetime lock armed by high taint, and a 600-second scoring window.

Two separate things are called containment, and they behave differently. One is a session-lifetime state that suspends grith's shortcuts; the other is a filter that adds score for ten minutes. They can be active at the same time and neither implies the other.

Sticky containment

Armed by registering a high-level taint - a read, write, chmod, rename or delete touching .ssh, id_rsa, id_ed25519, private_key or shadow. Direction does not matter: a write to ~/.ssh/authorized_keys arms it as surely as a read of ~/.ssh/id_rsa.

Medium-level taint - .env, .aws, credentials, secrets, .gnupg, .kube/config - does not arm it. That is deliberate, to keep ordinary startup reads of agent credential files from locking a session down.

It has no TTL. Once set it stays set. An attacker cannot wait it out. It clears only when the session ends, and the first reason is kept for forensics; the session_end audit record carries a containment_triggered flag.

What it does is suspend the shortcuts, so the pipeline gets to see everything:

  • The ignore_read_only fast path is bypassed.
  • The session allowlist is not consulted at all. Even a profile-trusted destination like api.openai.com re-runs the full pipeline.
  • Exact-command delegating approvals are suspended.
  • Approve replay and IPC grants are suspended.

One thing is not gated: the noise-path short-circuit. /proc, /sys, /dev/pts, /dev/tty and CA certificate directories stay noise regardless, because they were never carrying anything.

⚠️A retry wrapper clears it

Session lifecycle is user-initiated. A CI wrapper that automatically re-runs grith exec on failure starts a new session, which resets the scope and therefore clears containment. That is an operator choice, not a bug, but it is worth knowing you have made it.

Windowed containment

The session-containment filter is the second mechanism. It is one of the 18 and it contributes score like any other.

Armed by a read of a sensitive source, matched on path segment or basename, or by any call carrying taint. The window is 600 seconds and re-arms on each new trigger.

While the window is open it adds:

OperationAdded
Network or HTTP egress+4.5
Outbound-capable process spawn+4.0
Shell execution+3.5
Control-class unix socket - session D-Bus, X11, tmux, screen+2.0

Control sockets get the reduced figure on purpose: a keyring read under containment should not be pushed past the auto-deny line by the window alone.

Spawn scrutiny applies only to outbound-capable binaries. A contained session running a build - hundreds of rustc and linker spawns - is not penalised for any of them.

Which one you are looking at

StickyWindowed
Where it livesSession stateFilter 16 in the pipeline
TriggerHigh taint onlySensitive read or any taint
DurationThe whole session600 seconds, re-armable
EffectSuspends allowlists and replayAdds 2.0 to 4.5 to the composite
Visible in proxy testNoYes, as session-containment

If prompts are appearing for destinations you allowlisted, that is sticky containment. If scores are 4-ish higher than you expect but the allowlist still works, that is the window.

Releasing the window

The unlock-egress action on a digest item approves the call and unregisters the containment tracker for that session, which closes the window. It does not clear sticky containment - nothing does, short of ending the session.

See also

Last updated: 2026-08-24Edit this page on GitHub →