feat(sandbox): Fine-Grained Per-Command Permission Policies & Human Approval Gates

Open
#9 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
backend, security

Research direction

Start by reading tether/sandbox.py and tether/harness.py, then trace how SandboxPolicy.narrow_for_child(...), act(cmd, stdin), and session resumption work. The issue calls for tests covering writable path confinement, bash command prefixes, and the /approve and /reject resume lifecycle. Done means these policies and approval gates work while existing workspace-write and read-only profiles remain compatible.

Written by the indexing model from the issue text.

Description

enhancement

Summary & Motivation

As described in the Tether architecture blog post ("What Tether is still missing: 4. Approval gates and permission policies"):

"The sandbox is deterministic, but it is mostly all-or-nothing today. I want per-command policies in the envelope: this session may web fetch freely, may edit write only under docs/, and must pause and wait for a human before any bash that is not on an allowlist. A paused session would just be another state in SQLite, waiting in the inbox for a tether send. It is the same philosophy as the rest of the project: do not ask the model to be careful, make carefulness a property of the envelope."


Literature & State-of-the-Art Grounding

  1. System-Level Information Flow & Capability Security for LLM Agents:
    • Wu et al. (2024), "SecGPT: An Execution Isolation Architecture for LLM-Based Systems" (arXiv:2403.04960) & Bagdasaryan et al. (2024): Establish that because LLMs are vulnerable to indirect prompt injection from untrusted observations (web fetch, external files), access control must be enforced via fine-grained deterministic capability policies outside the LLM reasoning loop.
  2. Deterministic Policy Interceptors & Reference Monitors:
    • Debenedetti et al. (NeurIPS 2024), "AgentDojo: A Dynamic Environment to Evaluate Prompt Injection Attacks and Defenses for LLM Agents" (arXiv:2406.13352): Shows that combining path/command allowlists with Human-in-the-Loop (HITL) Reference Monitors on state-mutating actions prevents unauthorized side effects without degrading benign task completion.
    • Maia et al. (2026), "LLM-Native Applications as a Paradigm for AI-Driven Software Architecture": Security and permission boundaries must live in the deterministic envelope, never in system prompt instructions.

State-of-the-Art Fix & Architecture Design

1. Granular Policy Rules in SandboxPolicy (tether/sandbox.py)

Extend SandboxPolicy (backward-compatibly with profile="workspace-write" | "read-only") to support fine-grained capability rules:

  • writable_globs: list[str] | None = None: Confine edit write / edit replace to matching workspace subpaths (e.g., ["docs/**", "tests/**"]).
  • bash_allow_prefixes: list[str] | None = None: Commands matching these prefixes (e.g., ["pytest", "ruff", "git status", "git diff"]) execute immediately inside the sandbox.
  • require_approval_for: list[str] | None = None: Tool patterns or unlisted bash commands that trigger a deterministic Approval Gate (allow | ask | deny).
2. Pending Approval Interception via WAITING_APPROVAL / Inbox (tether/harness.py)

When the model emits act(cmd, stdin) that matches an ask (require approval) policy rule:

  1. The harness intercepts the action before executing mux.execute(cmd, stdin).
  2. Persists the pending (cmd, stdin) on the current turn and transitions the session to WAITING_INPUT / WAITING_APPROVAL with a clear prompt:
    [APPROVAL REQUIRED] Session `ses_...` wants to run: `bash rm -rf build/`
    Approve with `tether send ses_... "/approve"` or reject with `tether send ses_... "/reject <reason>"`.
    
  3. When the human operator (or parent orchestrator) sends /approve, the resumed worker executes the exact held (cmd, stdin) and continues; if /reject <reason>, it injects [ACTION REJECTED BY POLICY]: <reason> as the tool observation so the model can choose an alternative path.
3. Child Session Monotonic Narrowing (Rule 6)

Update SandboxPolicy.narrow_for_child(...) so child sub-agents spawned via agent spawn can only intersect/narrow writable_globs and bash_allow_prefixes, never widen them.

4. Acceptance Criteria
  • Fully backward-compatible with existing SandboxPolicy(profile="workspace-write") and read-only.
  • Zero additional tokens in the base system prompt (policy violations or rejections are reported JIT via observations).
  • Unit tests covering writable_globs confinement, bash_allow_prefixes, and the /approve / /reject resume lifecycle.
Dominant language
Python
Stars
3
Forks
1
Avg merge
52m
Merged PRs (30d)
166

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from igormcsouza/tether

All issues in igormcsouza/tether

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.