Open Source · Apache 2.0

Cloak

Real-time secret prevention for AI coding agents. Register secrets once — Cloak intercepts every tool call and substitutes live values at execution time, so your API keys and tokens never appear in the model context, conversation transcript, or MCP output.

View on GitHub

What It Does

When an AI agent runs a shell command like curl -H "Authorization: Bearer $STRIPE_KEY", the real key appears in the tool call payload — which gets serialized into the conversation transcript and sent to the model API. Cloak intercepts at the tool boundary and substitutes a placeholder, so the model only ever sees @@SECRET:stripe_key@@.

Cloak installs four hooks into your AI agent's settings, each covering a different exposure surface:

PreToolUse: Bash
Decloak

Substitutes @@SECRET:name@@ placeholders with real values before a shell command runs. Output is immediately re-cloaked before it reaches the transcript.

PostToolUse: mcp__.*
Re-cloak MCP

Scrubs real secret values from MCP tool responses before they are returned to the model, replacing any leaked values with their placeholders.

UserPromptSubmit
Prompt Guard

Scans every prompt you submit for recognizable secret patterns. Detected values are auto-registered and the prompt is soft-blocked, showing you a sanitized version to resubmit.

Stop (optional)
Residue Sweep

Runs a dry-run warden sweep after each session ends to catch any secrets that slipped through despite cloaking.

Cloak is the prevention layer. Sweep is the cleanup layer. Use both: Cloak to stop secrets entering the transcript in real time, Sweep to periodically audit for residue that may have accumulated before Cloak was installed.

How It Works

Secrets are stored as plain files under ~/.prismor/secrets/, one file per registered name. The directory is mode 0700 and each file is 0600 — accessible only by you, never committed to git, never synced by cloud tools.

Placeholder flow
# 1. You write a command using a placeholder
$ warden cloak add stripe_key       # registers @@SECRET:stripe_key@@

# 2. Agent generates a Bash tool call referencing the placeholder
curl -H "Authorization: Bearer @@SECRET:stripe_key@@" https://api.stripe.com/v1/charges

# 3. decloak.sh (PreToolUse hook) substitutes before execution
#    The real key is injected only into the shell subprocess — not the transcript
curl -H "Authorization: Bearer sk_live_..." https://api.stripe.com/v1/charges

# 4. Command stdout is piped through sed before the agent sees it
#    Any leaked real value in the output is replaced back with the placeholder
Authorization: Bearer @@SECRET:stripe_key@@

The hook scripts are pure bash + jq with no Python startup cost. The real value is never serialized into the Claude Code conversation JSON at any point.

Fail-closed by design.

If a @@SECRET:name@@ placeholder references a name that has no matching file in the secrets store, the Bash hook denies the tool call entirely rather than running with a missing substitution.

Setup

Requirements

  • bash — hook scripts run as bash (ships with macOS and Linux)
  • jq — JSON parsing for hook payloads
  • Python 3.8+ — Warden CLI runtime
  • Claude Code (or Cursor / Windsurf) — the agent being protected
Terminal
$ brew install jq

Install hooks

Run from your project root to wire the cloaking hooks into the current project's Claude Code settings:

Terminal
$ warden cloak install
Output
Installed cloaking hooks at /your/project/.claude/settings.json
  hooks: PreToolUse:Bash, PostToolUse:mcp__.*, UserPromptSubmit
  secrets dir: /Users/you/.prismor/secrets (0 registered)

Next step: register your first secret
  warden cloak add stripe_key

To protect all projects at once, install into your global settings instead:

Terminal
$ warden cloak install --scope user

Install flags

FlagDescription
--scope projectInstall hooks into the current project's .claude/settings.json (default)
--scope userInstall hooks into your global ~/.claude/settings.json — covers all projects
--no-userprompt-guardSkip the UserPromptSubmit soft-block hook (opt out of prompt scanning)
--sweep-on-stopAlso wire a Stop hook that runs a dry-run sweep after each session ends

Managing Secrets

Add a secret

Register a secret under a placeholder name. The value is read from a hidden prompt or piped from stdin — it never appears in your shell history.

Terminal
$ warden cloak add stripe_key
Enter value for stripe_key (hidden): ••••••••••••••••••••••••••
Registered @@SECRET:stripe_key@@ → ~/.prismor/secrets/stripe_key

To register from a file (useful for long keys or certificates):

Terminal
$ warden cloak add my_cert --from-file ./certs/server.pem

Once registered, reference the secret anywhere in a command or prompt using its placeholder:

curl -H "Authorization: Bearer @@SECRET:stripe_key@@" https://api.stripe.com/v1/charges

List registered secrets

Shows names, sizes, modification times, and whether a secret was auto-registered by the prompt guard. Values are never displayed.

Terminal
$ warden cloak list
  stripe_key          32 bytes   2026-04-09 11:23
  openai_key          51 bytes   2026-04-09 09:41
  auto_3f2a1b4c [auto] 40 bytes  2026-04-09 10:05

3 secret(s) registered in /Users/you/.prismor/secrets

Secrets tagged [auto] were created automatically by the UserPromptSubmit guard when it detected a raw secret value in a prompt you submitted.

Remove a secret

Terminal
$ warden cloak remove stripe_key
Removed @@SECRET:stripe_key@@ from /Users/you/.prismor/secrets

Check status

Terminal
$ warden cloak status
config:   /your/project/.claude/settings.json
installed: true
hooks:
  • PreToolUse: Bash
  • PostToolUse: mcp__.*
  • UserPromptSubmit
secrets dir: /Users/you/.prismor/secrets
registered:  3 secret(s)

Prompt Guard

The UserPromptSubmit hook scans every message you send before it reaches the model. If it detects a recognizable secret pattern, it blocks the submission and shows you a sanitized version to resubmit — with each secret replaced by a @@SECRET:auto_xxxxxx@@ placeholder that is automatically registered in the store.

Example: detected secret in prompt
# You type:
Fix the Stripe integration — the key is sk_live_AbCdEfGhIjKlMnOp1234

# Prompt guard fires before the message is sent:
Prismor cloaking: detected secret(s) in your prompt.

Stored under /Users/you/.prismor/secrets as:
  • @@SECRET:auto_3f2a1b4c@@

Resubmit with the sanitized version below:
---
Fix the Stripe integration — the key is @@SECRET:auto_3f2a1b4c@@
---

Detected secret patterns

The guard uses conservative, known-prefix patterns to minimize false positives:

ProviderPatterns
Stripesk_live_*, sk_test_*, rk_live_*
GitHubgithub_pat_*, ghp_*, gho_*, ghs_*, ghu_*
AWSAKIA* (access key), ASIA* (temp access key)
GoogleAIza* (API key)
Slackxox[bpoar]-*
GitLabglpat-*
JWTeyJ*.eyJ*.*

Bypassing the guard

If you are intentionally discussing a secret in prose (e.g. explaining a rotation procedure), prefix your message with !!allow to skip detection for that single submission:

!!allow The old key sk_live_... has been rotated. Please update the docs to reflect the new format.

The bypass applies only to that one message. The next submission is scanned normally.

Commands

CommandDescription
warden cloak add <name>Register a new secret interactively (value hidden at prompt)
warden cloak add <name> --from-file <path>Register a secret by reading its value from a file
warden cloak listList registered secret names, sizes, and timestamps (values never shown)
warden cloak remove <name>Delete a registered secret from the store
warden cloak statusShow hook installation state and registered secret count
warden cloak uninstallRemove all cloaking hooks from settings.json

Environment variables

VariableDescription
PRISMOR_SECRETS_DIROverride the secrets store location (default: ~/.prismor/secrets)

Examples

Example 1: Setting up a new project

You're starting a new project that uses Stripe and an OpenAI key. Install Cloak and register your secrets before your first agent session.

Terminal
# Install hooks into this project
$ warden cloak install

# Register your secrets (values hidden at prompt)
$ warden cloak add stripe_key
$ warden cloak add openai_key

# From now on, use placeholders in your prompts to Claude:
# "Run the Stripe charge using @@SECRET:stripe_key@@"
# Claude will use the real value at execution time — you never see it in the transcript.

Example 2: Protecting an existing workflow

You've been using Claude Code with real secrets in your prompts. Install Cloak, register your secrets, and the prompt guard will catch any future paste accidents automatically.

Terminal
# Install globally so all projects are covered
$ warden cloak install --scope user

# Register an existing token from a file
$ warden cloak add github_token --from-file ~/.secrets/github_token
Registered @@SECRET:github_token@@ → ~/.prismor/secrets/github_token

# Verify
$ warden cloak list
  github_token   40 bytes   2026-04-09 11:30

# The prompt guard now auto-catches if you ever paste the raw token by mistake.

The Secrets Store

Registered secrets live in a flat directory, one file per name:

~/.prismor/secrets/
  • Directory permissions: 0700 (owner read/write/execute only)
  • File permissions: 0600 (owner read/write only)
  • Each file is named after the placeholder (e.g. stripe_key)
  • Values are stored in plaintext — the filesystem permissions are the protection layer
  • Auto-registered secrets use a deterministic SHA-256 prefix name (auto_3f2a1b4c), so the same value always maps to the same placeholder across sessions

Do not sync your secrets directory.

If ~/.prismor/secrets/ is inside a directory that is backed up by iCloud, Dropbox, or similar, exclude it explicitly. Cloak is designed for local-only use.

Limitations to be aware of.

  • Cloak cannot protect short or hand-typed secrets (e.g. a 6-digit PIN) — the prompt guard uses known-prefix patterns only.
  • Freshly generated secrets (created during a session) are not automatically registered — you must run warden cloak add after generation.
  • Non-Bash tool calls (Python scripts invoked via MCP, etc.) are covered by the re-cloak hook on the response side, not the command side.