Outbound scrubbing
sable_scrub: true on a chat request makes the gateway redact known
secret/PII shapes from the outbound prompt before it reaches any vendor.
The redaction happens in memory at the egress shim (after the sealed
request is opened, before the upstream call), and each match is replaced with
a typed marker like [redacted:email] so the model can still reason about the
text's structure.
It is opt-in, per request, and works on both the OpenAI surface
(POST /v1/chat/completions) and the
Anthropic Messages API (POST /v1/messages):
curl https://api.buildsable.com/v1/chat/completions \
-H "Authorization: Bearer $SABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sable",
"sable_scrub": true,
"messages": [{"role":"user","content":"Summarize this log dump"}]
}'What gets redacted
The filter is deliberately conservative and pattern-based. It catches the shapes that are near-certainly secrets or contact identifiers:
| Shape | Matches | Becomes |
|---|---|---|
| Email address | local@domain.tld | [redacted:email] |
| EVM address / tx hash | 0x + 40 or 64 hex characters | [redacted:evm] |
| API keys & tokens | Common prefixes (sk-, sk_, ghp_, github_pat_, xoxb-, AKIA, AIza, eyJhbGciOi, …) and Bearer … values, 20+ chars | [redacted:key] |
| Long bare hex | 32+ contiguous hex characters (hashes, raw private keys, session tokens) | [redacted:hex] |
Where it runs: the §3 story
The privacy contract is unchanged by this feature, and the scrub is built inside it, not next to it:
- The request is sealed on ingress as always. The scrub runs after unsealing, inside the egress frame, immediately before the upstream call, the same short window where plaintext already exists.
- Nothing scrubbed or unscrubbed is ever stored or logged. The only new thing that reaches a log is the redaction count, which is content-free.
- The scrubbed text goes to the vendor; the original never leaves the frame.
The receipt proof
A scrubbed request's signed receipt carries
"scrubbed": true, proof that the filter ran on that request. The field is
present only when you opted in.
Honest limits
Read these before relying on it:
- Pattern-based, not NER. It catches secret shapes: emails, keys, wallet addresses, long hex. It does not catch names, addresses in prose, or any free-text PII. An opt-in redactor that silently mangled prose would be worse than none, so it doesn't try.
- This is redaction, not anonymization. The surrounding content still reaches the vendor in plaintext (on standard-tier routing, the host sees the prompt; see the privacy ladder). Scrubbing narrows what leaves; it does not change which rung you're on.
scrubbed: truemeans the filter executed, not that the prompt contained nothing sensitive afterward.
When to use it
The threat model is the agent stack handling untrusted input: a
prompt-injected agent pastes whatever it has into a model call, and whatever
it has often includes keys, wallets, and tokens. With sable_scrub: true on
the call (or baked into your agent's request wrapper), those shapes never
reach the upstream vendor at all, and the receipt proves the filter was on.