Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Expand Down Expand Up @@ -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.
Expand All @@ -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`:

Expand Down
14 changes: 9 additions & 5 deletions docs/threat_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) |
Expand All @@ -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 |
|---|---|
Expand Down