From 873d13e82fe88989f345c1dea1f31903dbcb5f59 Mon Sep 17 00:00:00 2001 From: BuckG71 <67705098+BuckG71@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:35:38 -0500 Subject: [PATCH] =?UTF-8?q?docs:=20align=20credential=20+=20network=20clai?= =?UTF-8?q?ms=20with=20code=20(known=5Fissues=20findings=203=E2=80=935)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README: soften the absolute "no credential of any kind ever enters" to the accurate claim — the MODEL credential never enters (always, via the broker); service tokens are kept out with onecli/hybrid, but a profile's `secrets:`/ `platforms:` block injects service tokens under `native`. Fixes the intro, the "What you get" bullet, and the Credential-privacy section (D-191). - threat_model §4.2: lead with the native broker as the default credential- mediation path; OneCLI is the opt-in extension (was framed as "the current integration"). Note the native+secrets service-token caveat. - threat_model §4.3: replace the stale "boolean only / unrestricted egress" with the five shipped network modes; arbitrary per-destination allowlist is the v1.0 item (points to network_egress_design.md). Doc-only. The profiles-table `build`="native" row is intentionally left pending the D-196 posture decision. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01PRQ6JeWxpD9zrYcPz6VFTS --- README.md | 6 +++--- docs/threat_model.md | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5814c33..fde9e13 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Run powerful agent harnesses inside explicit, temporary, auditable permission boundaries — on your own machine.** -Whizzard wraps an *agent harness* — a tool that drives an LLM through real work (Hermes today; Claude Code, Cursor, and others to follow) — in a hardened, time-bounded Docker sandbox. Inside it, the agent reaches only the files you mounted and the network you allowed. It never holds your model or service credentials; those stay on your machine. And you stay in the loop: capabilities only narrow after launch, any escalation needs your approval, and every session leaves an audit trail you can read back. +Whizzard wraps an *agent harness* — a tool that drives an LLM through real work (Hermes today; Claude Code, Cursor, and others to follow) — in a hardened, time-bounded Docker sandbox. Inside it, the agent reaches only the files you mounted and the network you allowed. It never holds your model credential — and, with OneCLI, your service tokens either; those stay on your machine. And you stay in the loop: capabilities only narrow after launch, any escalation needs your approval, and every session leaves an audit trail you can read back. > **Status:** v0.1.0 OSS launch in preparation. Jump to [Quickstart](#quickstart). @@ -50,7 +50,7 @@ The sandbox is the untrusted boundary. It never shares a network with anything h ## What you get - **Filesystem is opt-in.** The agent reaches only the paths you mounted — no parent-directory traversal, symlink, or glob trick reaches your home directory. The mount list *is* the permission model. Closes the whole "an agent ran `find ~ -name '*.pem'`" class. -- **Credentials never enter the sandbox.** A credential broker on your machine holds your real model key/login and attaches it only when forwarding to the model provider; the sandbox never sees the real value. If you use [OneCLI](https://onecli.sh), *every* service credential (GitHub, Slack, tool APIs) is injected on your machine too. A fully-compromised agent can neither read nor exfiltrate a secret it never holds. → [Credential privacy](#credential-privacy) +- **Your model credential never enters the sandbox.** A credential broker on your machine holds your real model key/login and attaches it only when forwarding to the model provider; the sandbox never sees the real value. If you use [OneCLI](https://onecli.sh), *every* service credential (GitHub, Slack, tool APIs) is injected on your machine too; without it, the `native` path still keeps your model key out (service tokens a profile declares are injected — see below). A fully-compromised agent can neither read nor exfiltrate a secret it never holds. → [Credential privacy](#credential-privacy) - **Network is a per-profile choice.** `off` = nothing (no DNS, no HTTP); `open` = full outbound access; `native` / `onecli` / `hybrid` = on, but outbound is routed so credentials stay out of the sandbox (see [Credential privacy](#credential-privacy)). `off` closes data exfiltration entirely. - **The container is hardened.** Non-root user, all Linux capabilities dropped, read-only container root, `no-new-privileges`, Docker socket unreachable. A vulnerable tool the agent invokes gets no root, no host, no escape hatch. - **Escalation is one-way, and you decide.** Permissions only narrow after launch. An agent that needs more surfaces a request to a file-mailbox you monitor; you approve or deny. No silent self-upgrade. @@ -59,7 +59,7 @@ The sandbox is the untrusted boundary. It never shares a network with anything h ## Credential privacy -**No credential of any kind ever enters the sandbox** — not your model key, not your service tokens. Whatever the agent uses, the real value stays on your machine and is attached to a request only as it leaves the sandbox for its real destination; inside the container there is only a placeholder. A fully-compromised agent cannot read or exfiltrate a secret it never holds. +**Your model credential never enters the sandbox** — the real key stays on your machine and is attached to a request only as it leaves the sandbox for the model provider; inside the container there is only a placeholder. Service tokens (GitHub, Slack, tool APIs) are kept out too when you use `onecli` or `hybrid`. The zero-dependency `native` path keeps your **model** key out; if a profile declares service tokens (a `secrets:` block, e.g. a platform bot token) those are injected into the sandbox under `native` — choose `onecli`/`hybrid` to keep them out as well. A fully-compromised agent cannot read or exfiltrate a secret it never holds. You choose **how** credentials are handled, based on how you sign in. Pick one of three — `whiz init` walks you through it, or set it per session with `--credential-handling`: diff --git a/docs/threat_model.md b/docs/threat_model.md index a3a4725..c6e4f04 100644 --- a/docs/threat_model.md +++ b/docs/threat_model.md @@ -222,7 +222,7 @@ that establishes it. | Defense | Reference | |---|---| -| Host-side credential mediation: credentials never enter the sandbox as plaintext env vars; sandbox-side HTTP traffic to model and platform endpoints is mediated by a host-side proxy (current integration is OneCLI) that injects credentials at the moment of the outbound request | D-91 / D-98 / D-134 | +| Host-side credential mediation: the **model** credential never enters the sandbox — the default `native` path runs a host-side **broker** (D-184) that holds the real key and injects it on the outbound model request; the sandbox holds only a placeholder. **OneCLI** (opt-in) extends this to every service credential via `onecli`/`hybrid` (D-187/D-188). Caveat: service tokens a profile declares in a `secrets:`/`platforms:` block are injected as env vars under `native` (kept out only under `onecli`/`hybrid`) | D-184 / D-187 / D-134 | | Host env fallback path emits a warning visible in `active_capabilities()` so operators see when credentials originate from less-protected sources | D-89 / D-90 | | Hermes `auth.json` and per-instance runtime state are excluded from profile clones (D-80); known bypass paths closed in prior internal review | D-80 / D-86 | | Whizzard's own config directory (`~/.whizzard/config/`) is structurally unreachable from the sandbox — no symlink, no parent-mount, no traversal trick reaches it | D-12 (config write-protection invariant) | @@ -231,10 +231,14 @@ that establishes it. ### 4.3 Network destinations -**v0.1.0 ships a boolean only**, not a per-destination allowlist. Profiles -declare `network_enabled: true | false`; off-network profiles launch with -`--network none` (no outbound, no DNS). On-network profiles get full -unrestricted egress. +**v0.1.0 ships five network modes** (`none`, `open`, `mediated`, `onecli`, +`hybrid`), not an arbitrary per-destination allowlist. `none` launches with +`--network none` (no outbound, no DNS); `open` gives full unrestricted egress; +`mediated`/`onecli`/`hybrid` put the sandbox on a per-session `--internal` +network whose only peers are host-side proxy sidecars — restricted egress +today (the sandbox has no direct route out). A profile-declared **allowlist** +of arbitrary destinations is the v1.0 item (ROADMAP goal 11); see +[`network_egress_design.md`](network_egress_design.md). | Defense | Reference | |---|---|