> ## Documentation Index
> Fetch the complete documentation index at: https://docs.claude-mem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Auto-Redaction

> Opt-in regex-based detection that replaces common secret patterns with <redacted/> placeholders before storage

# Auto-Redaction

claude-mem can automatically detect and redact common secrets before observations and summaries are stored. Unlike the manual [`<private>` tag](https://docs.claude-mem.ai/usage/private-tags), this is a deterministic regex pipeline that catches secrets you never typed yourself — for example, an API key printed by a `curl` response or echoed by a `Bash` command.

## How it works

When enabled, redaction runs at the same single point where `<private>` tags are stripped, so it covers the capture paths at once: tool inputs and outputs, your prompts (including stored prompt history) and the assistant's last message used for summaries. The [server runtime](https://docs.claude-mem.ai/hosted-server.md) also redacts every text value of an event body before it stores the event, and the worker and hook logs redact the tool line they write (for example a `Bash` command). One exception: server-runtime session and event **metadata** (such as the opening `prompt` in session metadata) is tag-stripped only when a string contains a tag, so redaction does not run on it. Content is scanned for a curated set of high-confidence secret patterns, and matches are replaced inline with a self-closing `<redacted type='...'/>` placeholder, preserving the surrounding context so search and observation quality stay intact.

```
Before:  curl -H "Authorization: Bearer sk-abc123def456..." …
After:   curl -H "Authorization: Bearer <redacted type='openai_key'/>" …
```

When a payload contains a marker, the observer prompt tells the model to treat it as a placeholder and not to infer the literal value. Prompts without markers are unchanged, so redaction adds no tokens when it finds nothing.

## Enable it

Add to `~/.claude-mem/settings.json`:

```json theme={null}
{
  "CLAUDE_MEM_REDACT_ENABLED": "true"
}
```

That is all you need for the 38 built-in patterns to kick in. Add `"CLAUDE_MEM_REDACT_GENERIC_ENABLED": "true"` to also turn on the 4 [generic patterns](#generic-patterns).

## Built-in patterns

| Name | Catches |
| - | - |
| `aws_access_key` | `AKIA…` and temporary `ASIA…` key IDs (16 trailing alphanumerics) |
| `aws_secret_key` | 40-char base64 anchored to `AWS_SECRET_ACCESS_KEY=…` in any letter case, as in `~/.aws/credentials`, or JSON `"SecretAccessKey": "…"` (`aws sts` output) |
| `aws_session_token` | 100+ char base64 anchored to `AWS_SESSION_TOKEN=…`, `aws_session_token = …` or JSON `"SessionToken": "…"` (temporary STS/SSO credentials) |
| `github_pat` | `ghp_…`, `gho_…`, `ghu_…`, `ghs_…`, `ghr_…`, `github_pat_…` |
| `openai_key` | `sk-…` (≥20 chars) |
| `anthropic_key` | `sk-ant-…` (≥20 chars) |
| `slack_token` | `xoxb-…`, `xoxp-…`, `xoxa-…`, `xoxr-…`, `xoxs-…`, `xoxe-…` (refresh), `xapp-…` (app-level) |
| `jwt` | `eyJ…[.]eyJ…[.]…` three-segment tokens |
| `private_key_pem` | `-----BEGIN [RSA\|DSA\|EC\|OPENSSH\|PGP\|ENCRYPTED\|]PRIVATE KEY[ BLOCK]-----` blocks |
| `stripe_key` | `sk_live_…`, `pk_live_…`, `rk_test_…`, `whsec_…` |
| `google_api_key` | `AIza…` (35 trailing chars) |
| `google_oauth_token` | `ya29.…` Google OAuth access tokens, including the `ya29.c.…` metadata-server form (≥20 trailing chars) |
| `gitlab_token` | `glpat-…`, `gldt-…` and `glrt-…` GitLab personal, project, group, deploy and runner access tokens (≥20 chars, routable `.`-segments included) |
| `huggingface_token` | `hf_…` Hugging Face access tokens |
| `npm_token` | `npm_…` npm access tokens (36 trailing alphanumerics) |
| `docker_pat` | `dckr_pat_…` Docker Hub personal access tokens (≥27 trailing chars) |
| `linear_key` | `lin_api_…` Linear personal API keys (40 trailing alphanumerics) |
| `notion_token` | `ntn_…` Notion integration tokens (46 trailing alphanumerics) and the older `secret_…` form (43) |
| `sendgrid_key` | `SG.…` SendGrid API keys (`SG.` + 22 + `.` + 43 chars) |
| `digitalocean_token` | `dop_v1_…`, `doo_v1_…`, `dor_v1_…` DigitalOcean personal access, OAuth and refresh tokens (64 hex chars) |
| `shopify_token` | `shpat_…`, `shpca_…`, `shppa_…`, `shpss_…` Shopify access tokens and shared secrets (32 hex chars) |
| `pypi_token` | `pypi-AgE…` PyPI API tokens (≥50 trailing chars) |
| `databricks_token` | `dapi…` Databricks personal access tokens (32 hex chars, optional `-<digit>` suffix) |
| `vault_token` | `hvs.…` HashiCorp Vault service tokens (90-120 trailing chars) and `hvb.…` batch tokens (138-300 trailing chars) |
| `nvidia_nim_key` | `nvapi-…` NVIDIA NIM keys from build.nvidia.com (≥32 trailing chars) |
| `runcrate_key` | `rc_live_…` Runcrate keys (≥24 trailing chars) |
| `groq_key` | `gsk_…` Groq API keys (52 trailing alphanumerics) |
| `xai_key` | `xai-…` xAI API keys (80 trailing chars) |
| `perplexity_key` | `pplx-…` Perplexity API keys (48 trailing alphanumerics) |
| `supabase_token` | `sbp_…` Supabase personal access tokens (40 hex chars) |
| `sentry_token` | `sntryu_…` Sentry personal auth tokens (64 hex chars) and `sntrys_…` organization auth tokens |
| `grafana_token` | `glsa_…` Grafana service account tokens (32 chars + `_` + 8 hex checksum) and `glc_…` Grafana Cloud tokens |
| `postman_key` | `PMAK-…` Postman API keys (24 hex + `-` + 34 hex) |
| `slack_webhook` | the secret of Slack incoming webhook URLs (`hooks.slack.com/services/T…/B…/…`, workflow and trigger URLs); the host and ids are kept |
| `discord_webhook` | the token of Discord webhook URLs (`discord.com/api/webhooks/<id>/<token>`, `discordapp.com` too); the host and id are kept |
| `claude_mem_key` | claude-mem's own server API keys (`cmem_…`) and cmem.ai Pro memory keys (`cm_pro_…`) |
| `cookie_header` | the value of a `Cookie:` or `Set-Cookie:` header, whatever the cookie is named (`curl -v` output, proxy logs, JSON header objects); the header name is kept |
| `url_credentials` | the password in `scheme://user:password@host` URLs (database URLs, `git remote -v`); the scheme, user and host are kept |

## Generic patterns

Credentials without a vendor prefix (a database password, an internal token) need a lower-confidence match on the key name. These four patterns are off until you opt in:

```json theme={null}
{
  "CLAUDE_MEM_REDACT_ENABLED": "true",
  "CLAUDE_MEM_REDACT_GENERIC_ENABLED": "true"
}
```

| Name | Catches |
| - | - |
| `generic_password` | values assigned to a `password` / `passwd` key or a `*_PWD` key (`DB_PASSWORD=…`, `MYSQL_PWD=…`), in shell, yaml or JSON style |
| `generic_token` | values assigned to a `*_TOKEN` / `*_SECRET` / `*_API_KEY` key (e.g. `AUTH_TOKEN=…`, `"client_secret": "…"`), and to a bare `token` / `secret` / `api_key` key in config-style positions only: a quoted JSON key (`"secret": "…"`), an env or query assignment (`api_key=…`, `?token=…`), a CLI flag, prefixed ones included (`--token=…`, `--api-key …`, `--auth-token …`, `--client-secret=…`) or a yaml line (`token: …`). Source code such as `const token = getToken();` is left alone |
| `bearer_token` | the value after `Authorization: Bearer …` or `Proxy-Authorization: Bearer …` |
| `basic_auth` | the credentials after `Authorization: Basic …` or `Proxy-Authorization: Basic …` (base64 of `user:password`) |

They run **after** every vendor pattern, so a vendor-shaped value (a `sk-…` key, a JWT, …) keeps its specific marker. To keep false positives away they only fire when the value is 8+ characters, contains at least one letter, and consists solely of secret-typical characters — so `max_tokens=4096`, short PINs, purely numeric values and the `PWD` / `OLDPWD` working-directory variables are left alone. In server-runtime event bodies, a string value under a credential-named key (`client_secret`, `db_password`, `MYSQL_PWD`, `token`, …) is redacted whole. Like every built-in, each can be disabled by name.

## Disable a single built-in

```json theme={null}
{
  "CLAUDE_MEM_REDACT_ENABLED": "true",
  "CLAUDE_MEM_REDACT_DISABLED_BUILTINS": "jwt,slack_token"
}
```

CSV format. The other built-ins stay active.

## Add a custom pattern

```json theme={null}
{
  "CLAUDE_MEM_REDACT_ENABLED": "true",
  "CLAUDE_MEM_REDACT_CUSTOM_PATTERNS": "[{\"name\":\"company_internal_token\",\"regex\":\"INTERNAL-[A-Z0-9]{32}\"}]"
}
```

`name` is required and surfaces in the `<redacted type='...'/>` marker. Custom patterns are evaluated **before** built-ins, so you can override the built-in detection for a specific token family.

If your regex fails to compile or your JSON is malformed, claude-mem logs a warning and skips the broken entry — the rest keep working.

## Diagnostic logging

```json theme={null}
{
  "CLAUDE_MEM_REDACT_LOG_MATCHES": "true"
}
```

Writes a `pattern,count` line per invocation to the worker log. The original matched bytes are never logged.

## Limits

* **Fails closed on huge fields**: a single field over about 1M characters (UTF-16 code units) is replaced whole by `<redacted type='oversize'/>` rather than stored unscanned, and a warning is logged. There is no cap on the number of matches: every match is redacted.
* **Coverage gap**: Built-ins do not cover Azure / GCP service-account JSON / IBM Cloud / private IDC tokens — use custom patterns for those.
* **Unreadable settings.json**: if the file stops parsing (for example after a bad hand edit) while redaction is on, claude-mem keeps redacting, with the last configuration that loaded or the built-in patterns, and logs a warning. It does not fall back to the default (off). Repair the file to change the configuration, or set `CLAUDE_MEM_REDACT_ENABLED=false` in the environment to turn redaction off.
* **Server-beta scope**: in multi-tenant `server-beta` deployments, the redaction config is currently read from the worker's local `~/.claude-mem/settings.json` rather than from tenant-scoped settings. For team deployments, configure redaction at the worker level. A future change will source tenant-scoped redaction config.
* **Destructive**: this is destructive replacement, not encryption. Redacted bytes cannot be recovered. If you need reversible protection, use the `<private>` tag and keep the secrets out of the conversation entirely.

## Comparison with `<private>` tags

| | `<private>` (manual) | Auto-redaction |
| - | - | - |
| **Trigger** | User wraps `<private>...</private>` | Regex match anywhere in content |
| **Granularity** | Whole block dropped | Inline placeholder, surroundings kept |
| **Default** | Always on (no setting) | Off until you opt in |
| **Use when** | You know up front the content is sensitive | You want a safety net for accidental token leaks |

Both can be used together — `<private>` blocks are removed first, then auto-redaction scans what remains, so a wrapped `<private>` block has its content removed entirely regardless of what's inside.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.