sandbroker
A typed-return secret executor. Claude Code causes secrets to be used without ever learning what they are.
Full design, threat model, and hardening guide live in docs/:
start with docs/SECURITY.md,
docs/THREAT-MODEL.md, and DEPLOY.md.
This README is the short version.
The claim
No plaintext secret resolved by sandbroker appears in Claude's context, in the Anthropic API request body, in the local session transcript, or in any prompt cache, because no channel exists through which it could travel.
It does not claim anything about secrets arriving through doors sandbroker
doesn't mediate. "100% secure" is not on offer; see the known limits in
docs/SECURITY.md.
Why not a redaction hook
A PostToolUse redaction hook is a filter, and filters fail open: unmatched
pattern, unexpected encoding, or an unanticipated error string, and the raw value
proceeds to the wire. sandbroker is not a filter. The response schema has no field
a secret can occupy.
How it holds
Four structural properties, all asserted in tests/test_guarantee.py (30 tests):
- The child cannot talk to us. Targets spawn with stdout/stderr bound to
/dev/nullat the fd level, so no output on any path reaches the caller. - Secrets never enter
argv. Rejected at registry load, because/proc/PID/cmdlineexposes argv to the same uid. - There is no shell. Argv vectors only, so arguments can never become code.
- Egress is allowlisted. Response keys outside
{ok, error, verb}are dropped and unknown error tokens collapsed.
Install
Two commands on Linux/WSL2 or macOS. First make sure pipx is installed
(sudo apt install pipx on Debian/Ubuntu/WSL2, brew install pipx on macOS; a
PEP 668 "externally-managed" Python blocks pip install pipx):
pipx install sandbroker # puts sandbroker, sandbrokerd, and the bin/ helpers on PATH
sandbroker setup # guided wizard: base + daemon, secret store, approver, Claude Code
sandbroker setup runs unprivileged (user mode) by default; add --hardened for
the dedicated-uid /opt/sandbroker system install. See
docs/integration-notes/setup-wizard.md.
Quick start from a checkout (Linux/WSL, systemd)
python3 tests/test_guarantee.py # expect OK
sudo ./install.sh # creates sandbroker uid + claude-broker
install -m 0755 bin/sandbroker ~/.local/bin/sandbroker
install -m 0755 hooks/deny_secret_reads.py ~/.claude/hooks/
# new login session for group membership, then:
sudo ./canary/canary_provision.sh
sandbroker canary.probe --ref file://canary # expect {"ok": true}
sudo ./canary/canary_sweep.sh # expect clean
Then register the PreToolUse hook in your Claude Code
settings.json (see docs/ for the snippet).
Ref schemes
| Scheme | Backend |
|---|---|
file://canary |
local 0400 file, verification only |
akv://<vault>/<name> |
Azure Key Vault via az |
op://<vault>/<item>/<field> |
1Password via the op CLI |
op:// refs name an alias from the root-owned vault registry, not a real
vault; akv:// and the canary bypass the registry entirely. Which backend to
choose, how to wire each one up, and why none of it is editable from the web
console: docs/vaults.md.
Layout
sandbroker/sandbrokerd.py the daemon: exec core, registry validator, egress filter
sandbroker/verbs.json capability grants; installed root:root 0444
bin/sandbroker the only interface Claude uses
hooks/ PreToolUse deny for doors sandbroker doesn't mediate
canary/ provision + sweep: the leak test that must keep passing
tests/ the guarantee, as executable assertions
install.sh every sudo step (Linux/systemd)
Verification note
A sweep only means something when Claude runs the probe. Running it yourself proves nothing, because the canary was never near the model's context. Have Claude exercise the verbs and attempt extraction, then sweep.
Metadata
Release files for sandbroker 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sandbroker-0.2.0.tar.gz | 138.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sandbroker-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 263.6 kB
Release files / sandbroker-0.2.0.tar.gz
| Download URL | sandbroker-0.2.0.tar.gz |
|---|---|
| Size | 138.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b438756957daca75bd8c04fc61c1817ab92bad97cc36e1119b116fc3d98c951
|
|
BLAKE2b-256 checksum How to use checksums |
ce780165f97f43dabb3ae5c108154115e838f54c0e303c8d23235bc57248c7fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency logRelease files / sandbroker-0.2.0-py3-none-any.whl
| Download URL | sandbroker-0.2.0-py3-none-any.whl |
|---|---|
| Size | 125.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
509b9efbe11b2667ff31e6bde9dbc101e21275f138e171ca6de24cedd320f228
|
|
BLAKE2b-256 checksum How to use checksums |
2d0f4187ef9f3c226b07fd618a2340ce2e062432106639e39268a8a5f40eb356
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 3, 2026.
Transparency log