Local secret redaction

PromptCloak

Run a small proxy or Python filter before your LLM backend. PromptCloak removes keys, tokens, passwords, private keys, and signed URLs from request bodies before they leave your machine.

Local only No telemetry Proxy or library
Secrets stay local Request bodies are cleaned before forwarding.
Library mode Filter messages before SDK calls.
Provider agnostic OpenAI-compatible routes and Anthropic pass-through.

Verify

See what upstream receives.

Start locally, point your client at 127.0.0.1:8000, and use an echo target for redaction checks. Model replies are not reliable evidence.

brew tap bvolpato/tap
brew install promptcloak
promptcloak init
export OPENROUTER_API_KEY="<openrouter-upstream-key>"
promptcloak serve
FAKE_KEY="AI""zaSyFixtureToken000000000000000000000"
curl -fsS http://127.0.0.1:8000/v1/chat/completions \
  -H "X-Target-Base-URL: https://httpbin.org/anything" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"content":"GEMINI_API_KEY='"$FAKE_KEY"'"}]}'

# upstream body: GEMINI_API_KEY=[REDACTED_SECRET]

Install

Install once. Point clients at localhost.

Use PromptCloak as a local proxy for agents, or import it before direct SDK calls.

brew tap bvolpato/tap
brew install promptcloak
promptcloak init
export OPENROUTER_API_KEY="<openrouter-upstream-key>"
promptcloak serve
curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"content":".env has sk-..."}]}'
from promptcloak import redact_messages

safe = redact_messages([
  {"role": "user", "content": "API_KEY=<secret>"}
])

Proxy mode

Forward without reshaping requests.

PromptCloak redacts JSON and text bodies, then forwards the original route and provider-specific fields.

Dynamic upstreams

curl http://127.0.0.1:8000/v1/responses \
  -H "X-Target-Base-URL: https://api.openai.com/v1" \
  -H "X-Target-API-Key: $OPENAI_API_KEY"

Default config

target:
  default_base_url: https://openrouter.ai/api/v1
  api_key: ${OPENROUTER_API_KEY}
  api_key_header: authorization
redaction:
  engine: detect-secrets
  redact_mode: full

Routes

/v1/chat/completions
/v1/responses
/v1/completions
/v1/models
/v1/messages

Library

Use it in-process.

Import PromptCloak helpers before OpenAI, LiteLLM, LangChain, Anthropic, or custom HTTP client calls.

OpenAI

from openai import OpenAI
from promptcloak import redact_messages

client = OpenAI()
client.chat.completions.create(
  model="gpt-5.5",
  messages=redact_messages(messages),
)

LiteLLM

from litellm import completion
from promptcloak import redact_params

messages = [{"role": "user", "content": "API_KEY=<secret>"}]

completion(**redact_params(
  model="openrouter/openai/gpt-5.5",
  messages=messages,
))

Responses API

from promptcloak import redact_params

client.responses.create(**redact_params(
  model="gpt-5.5",
  input="OPENAI_API_KEY=<secret>",
))

LangChain

from langchain_openai import ChatOpenAI
from promptcloak import redact_messages

llm = ChatOpenAI(model="gpt-5.5")
llm.invoke(redact_messages([
  ("human", "token=<secret>"),
]))

Anthropic

from anthropic import Anthropic
from promptcloak import redact_messages

Anthropic().messages.create(
  model="claude-opus-4-8",
  max_tokens=1024,
  messages=redact_messages(messages),
)

LlamaIndex

from llama_index.llms.openai import OpenAI
from promptcloak import redact_messages

llm = OpenAI(model="gpt-5.5")
llm.chat(redact_messages(messages))

Agent configs

Agent configs stay plain.

Codex

# ~/.config/promptcloak/config.yaml
target:
  forward_client_authorization: true

compat:
  responses_to_chat: true

# ~/.codex/openrouter-promptcloak.config.toml
model = "openai/gpt-oss-120b"
model_provider = "promptcloak-openrouter"

[model_providers.promptcloak-openrouter]
name = "PromptCloak OpenRouter"
base_url = "http://127.0.0.1:8000/v1"
env_key = "OPENROUTER_API_KEY"
wire_api = "responses"
request_max_retries = 0
stream_max_retries = 0

# PromptCloak forwards localhost auth and bridges Responses to Chat.

OpenCode

{
  "provider": {
    "promptcloak": {
      "npm": "@ai-sdk/openai-compatible",
      "options": {
        "baseURL": "http://127.0.0.1:8000/v1",
        "headers": {
          "X-Target-Base-URL": "https://openrouter.ai/api/v1",
          "X-Target-API-Key": "{env:OPENROUTER_API_KEY}"
        }
      }
    }
  }
}

Claude Code

export ANTHROPIC_BASE_URL="http://127.0.0.1:8000"
export ANTHROPIC_API_KEY="${PROMPTCLOAK_LOCAL_API_KEY:-placeholder}"
export DISABLE_TELEMETRY=1

Smoke tests

Do not ask a model to echo secrets.

Use an echo target to inspect exactly what upstream receives. Do not ask a model to repeat secrets back as a redaction test.

FAKE_KEY="AI""zaSyFixtureToken000000000000000000000"

curl -fsS http://127.0.0.1:8000/v1/chat/completions \
  -H "X-Target-Base-URL: https://httpbin.org/anything" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"content":"GEMINI_API_KEY='"$FAKE_KEY"'"}]}' \
  | jq -r '.json.messages[0].content'

Deploy

Keep it local unless you mean to share it.

Keep PromptCloak bound to localhost for personal use. If you expose it to a network, set an allowlist and local proxy API key.

Docker

docker run -d --name promptcloak --rm \
  -p 127.0.0.1:8000:8000 \
  -e PROMPTCLOAK_TARGET_BASE_URL=https://openrouter.ai/api/v1 \
  -e PROMPTCLOAK_TARGET_API_KEY="$OPENROUTER_API_KEY" \
  ghcr.io/bvolpato/promptcloak:0.1.5

curl -fsS http://127.0.0.1:8000/healthz

Helm

helm install promptcloak \
  https://github.com/bvolpato/promptcloak/releases/download/v0.1.5/promptcloak-0.1.5.tgz \
  --set secretEnv.PROMPTCLOAK_TARGET_API_KEY="$OPENROUTER_API_KEY"

kubectl wait deployment/promptcloak --for=condition=Available --timeout=90s
kubectl port-forward svc/promptcloak 8000:8000
curl -fsS http://127.0.0.1:8000/healthz

Homebrew

brew tap bvolpato/tap
brew install promptcloak
promptcloak version

Library

uv add \
  https://github.com/bvolpato/promptcloak/releases/download/v0.1.5/promptcloak-0.1.5-py3-none-any.whl

from promptcloak import redact_payload
safe_payload = redact_payload(payload)

Coverage

Credential families covered by tests.

Deterministic patterns cover provider keys, personal access tokens, JWTs, signed URLs, private key blocks, URL credentials, and assignment-style secrets.

GitHub PATs Atlassian OpenAI Gemini Anthropic OpenRouter Z.AI MiniMax DeepSeek Codex Grok/xAI Fireworks Cloudflare AWS Signed URLs PGP keys Slack Stripe JWTs PEM keys Custom rules

Security model

Small privacy boundary.