Secret Paste Guard
Secret Paste Guard is a shipped, opt-in feature that keeps API keys and other secrets out of your AI conversation history: paste a secret into the session composer and Omniscio stores it locally under an opaque handle, substituting the real value only at execution time on Claude-based engines.
What it is
Secret Paste Guard is a shipped, opt-in feature (off by default) that keeps API keys and other secrets out of your AI conversation history. When you paste a secret into the session composer, Omniscio stores it locally under an opaque handle. For Claude-based engines it injects the real value only at the moment the agent actually uses it — in a shell command, a file write, or a web-form field — so the raw value never enters the model's conversation. For every engine, Omniscio's own stored history is scrubbed of the value. The protection is honest about what each engine can and can't do (see "The guarantee").
Where to find it
How to use it
Turn it on. Secret Paste Guard ships off by default — turn it on at Settings → Features → "Secret Paste Guard" (the
secretHandleEnabledsetting). Nothing about it runs until you enable it.Paste your secret into the composer. When the feature is enabled and Omniscio detects that what you typed looks like an API key or secret, it offers to store it securely.
The secret is stored locally. Omniscio saves the raw value in an encrypted, per-session store on your machine. On a Claude-based engine it also replaces the value in the composer with the opaque handle (
AMCSECRET-<hex>) — that handle is what the AI sees. On another engine it keeps the raw value in place (so the engine's tools still work) but tells you plainly that the engine still receives the key.The agent works with the handle (Claude engines). When the agent writes a shell command or file containing the handle, a PreToolUse hook substitutes the real value at execution — before the command runs — so the secret reaches its destination without appearing in the chat. Once the session ends, a log-scrub also cleans the value out of the Claude CLI's own local transcript.
Turn it off. Toggle secretHandleEnabled off in Settings; pasted secrets are then treated as plain text (the previous behavior).
How it behaves
What problem it solves
Normally, if you paste an API key directly into a chat message, that value lives in your history
forever: in the database, in search indexes, in exports, and — for Claude engines — in the Claude
CLI's own local transcript. Secret Paste Guard intercepts the secret before it gets that far. On
Claude-based engines the model only ever sees a placeholder like AMCSECRET-a3f9b2…; the real
value is substituted in privately, at execution time, by a hook that runs outside the
conversation. On other engines the value still reaches the engine, but Omniscio keeps it out of
your saved, searchable history.
The guarantee — three honest tiers by engine
Every engine: Omniscio's own stored history is always scrubbed — the raw value is never
written to conversation_messages, never indexed for search, never included in exports, and
never shown in the live chat (a persistence scrub strips it even if an agent echoes it back).
Tier 1 — Claude-based engines (the native Claude CLI plus the vendors that reuse it): the model never sees the value. The composer swaps your paste for a handle, and the PreToolUse hook substitutes the real value only at execution. A log-scrub also cleans the value out of the Claude CLI's own local transcript once the session's process exits.
Tier 2 — codex / gemini / cursor (planned fast-follow): server-side secret tools will let these engines use a stored key without the model seeing the raw value. Until that lands they run in the partial tier below.
Tier 3 — every other engine: partial protection. The key is kept in the composer so the engine's tools still work, but it is stored so Omniscio's saved history is scrubbed — the engine (and its own logs) still receive the value, and the offer says so honestly.
Honest residual (inherent): for the secret to be usable, it must be reachable at execution, so an actively-compromised or prompt-injected agent could still use or exfiltrate it. The guarantee is "never passively persisted in Omniscio history; scrubbed from the local Claude transcript" — not "immune to an actively-hijacked agent," the same trade-off other credential-proxy patterns accept.
Scope
- Full substitution (Tier 1) = the Claude-binary family — the native Claude CLI plus the vendors that reuse it. SSH/remote is out of scope.
- codex / gemini / cursor (Tier 2) get server-side secret tools as a planned fast-follow; until then they run in the partial tier.
- Every other engine (Tier 3) gets partial protection — Omniscio's saved history is scrubbed, but the engine still receives the value.
- Web-form fill via the AI Browser (
type/fill_formwith asecretHandle) resolves the value server-side. - The feature is desktop-only. The stash channel that accepts the secret is not reachable from the mobile or web bridge (blocked by design — a headless secret-injection endpoint would be a security risk).
Where secrets are stored
Secrets are kept in a per-session, file-based store at <userData>/session-secrets/<id>.json,
encrypted with Electron's OS keyring (safeStorage — Windows DPAPI / macOS Keychain / Linux
libsecret). If safeStorage is unavailable, secrets are kept in memory only and never written
to disk as plaintext. The store is cleared when the session is deleted or reaches its retention
limit. There is no database table; no migration was added.
See also
- INDEX.md
- api-keys.md — manage and view stored API keys and secrets in one inventory
- automation-credentials.md — saved credentials for v2 automation actions (a separate, complementary secret-storage layer)
- git-guardrails.md — the PreToolUse hook system Secret Paste Guard composes alongside
For agents
For AI agents
- Detection: the shared
detectPotentialSecretclassifier flags a pasted value as secret-shaped; negative results pass through as normal text. - Engine-aware offer:
SESSION_STASH_SECRET(IPC) accepts a secret and returns the handle plus aswapflag =usesClaudeBinary(provider). The renderer swaps the value for the handle ONLY whenswapis true (Tier 1); otherwise it keeps the raw value (Tier 3 partial), so a non-substituting engine is never handed a handle it cannot expand (secret-stash-apply.ts). The channel returns only the handle (never the value), is a CLI-parity exemption, and is inBLOCKED_CHANNELS. - Substitution hook (Tier 1): a bundled
PreToolUsehook (resources/secret-substitution/secret-substitution.mjs) fast-paths when noAMCSECRET-is present. On any error or timeout it emits no output and exits 0 — the literal handle stays and the action fails harmlessly (fail-safe, never a leak). A co-residentdenyhook from git-guardrails still wins (deny is terminal). - Transcript log-scrub (Tier 1): when a session's Claude CLI process EXITS (the
sessionEndbus — file closed, safe to rewrite), the value the hook injected (which Claude logs into its own~/.claudetranscript) is rewritten back to its handle (transcript-secret-scrub.ts): raw + JSON-escaped forms, per-line integrity revert (never invalid JSON), atomic temp+rename, self-gated onhasSecrets, kill-switchAMC_DISABLE_SECRET_TRANSCRIPT_SCRUB. - Resolve route:
POST /session/secret/resolve(src/main/services/cli/cli-server-secret-routes.ts) 404s when the feature is hidden, requires bearer auth, and expands handles only for theX-AMC-Source-Session-Idsession — never cross-session. - Gate: the spawn wiring checks both
isUnreleasedFeatureVisible('secret-handle', …)ANDresolveSecretHandleEnabled(…)in src/main/process/secret-handle-gate.ts; the renderer composer offer checksisSecretHandleActiveInRenderer(settings)— both key on thesecretHandleEnabledsetting (not visibility), so there's zero per-tool-call/paste cost when off. - Handle format:
AMCSECRET-<>=12 hex chars>(SECRET_HANDLE_RE/makeSecretHandle). - Persistence scrub (every engine):
redactSessionSecrets(sessionId, content)runs insideprepareAddMessage(src/main/db/queries-messages/write.ts) before any cap, derive, index, or store step AND before the returned message content reaches the renderer — so a value an agent echoes is stripped from both the database and the live UI. - Guarding tests: secret-detection.test.ts, session-secret-store.test.ts, secret-handle-gate.test.ts, transcript-secret-scrub.test.ts, transcript-scrub-on-session-end.test.ts, secret-stash-apply.test.ts.
Related
api-keys.md covers managing and viewing stored API keys in one inventory, automation-credentials.md the separate and complementary secret-storage layer for automation actions, git-guardrails.md the hook system this feature composes alongside, and INDEX.md is the library index.
Last verified 2026-09-23