Tools
Redacter
Defense-in-depth secret redaction OpenClaw plugin. Intercepts and irreversibly redacts secrets before any content reaches the LLM and sanitizes OpenClaw-owned transcripts/tool-result persistence.
Install
npm install
npm
Configuration Example
{
"extensions": ["/absolute/path/to/openclaw-redacter/dist/index.js"]
}
README
# Redacter — OpenClaw Secret Redaction Plugin
<!-- Banner -->
<picture>
<img src="./docs/images/banner.webp" alt="openclaw-redacter banner" />
</picture>
<!-- Badges -->
<p>
<a href="https://www.npmjs.com/package/openclaw-redacter">
<img src="https://img.shields.io/npm/v/openclaw-redacter/latest" alt="npm version" />
</a>
<a href="https://github.com/SBTopZZZ-LG/openclaw-redacter/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/SBTopZZZ-LG/openclaw-redacter" alt="License" />
</a>
<a href="https://github.com/SBTopZZZ-LG/openclaw-redacter/actions">
<img src="https://github.com/SBTopZZZ-LG/openclaw-redacter/actions/workflows/cd.yaml/badge.svg" alt="Release workflow" />
</a>
</p>
Defense-in-depth secret and sensitive-content redaction for OpenClaw. Intercepts
and irreversibly redacts secrets before any content reaches the LLM, and
sanitizes OpenClaw-owned transcript and tool-result persistence.
The plugin is written in TypeScript, depends on no runtime libraries, and is
intentionally narrow: v1 supports **irreversible** redaction only. No
deterministic placeholders or reversible tokenization.
## What it does
- Scans every model-bound payload (system prompt, user prompt, history
messages, tool params, tool results) for known secret formats and
structured key/value pairs.
- Replaces detected secrets with irreversible markers such as
`[REDACTED:API_KEY]`, `[REDACTED:JWT]`, `[REDACTED:AWS_ACCESS_KEY_ID]`, etc.
- Treats `before_agent_run` as the **primary final barrier**. When configured
in `strict` mode, a detected secret in that hook blocks the agent run
with a sanitized, classified reason that OpenClaw's `InputGateDecision`
contract handles.
- Sanitizes OpenClaw-owned transcript writes via `tool_result_persist` and
`before_message_write` (synchronous rewrite of the persisted message).
- Wires additional defense-in-depth hooks: `before_prompt_build`,
`llm_input`, `before_tool_call`, `after_tool_call`, `message_received`,
`message_sending`, and `message_sent`.
- Logs only **sanitized summaries** of detections. The audit pipeline is
structurally incapable of emitting a raw secret value.
## Threat model
Defend against:
- API keys, OAuth tokens, JWTs, session tokens, basic/bearer credentials.
- Cloud credentials: AWS access keys, AWS secret access keys (length-40
base64-ish), GCP API keys, Stripe keys, etc.
- VCS tokens: GitHub classic + fine-grained PATs, GitLab PATs, Slack tokens.
- Private key blocks (PEM) and SSH public-key strings.
- `.env` style secrets, JSON/YAML key-value pairs with secret-shaped keys,
connection strings / DSNs, webhook URLs with `?secret=` / `?token=`
query params.
Out of scope for v1:
- Reversible tokenization / vault-based re-injection.
- Provider-side encryption of transcripts.
- Anti-prompt-injection for instructions (this plugin's scope is secret
redaction only).
## Install
### From npm
```bash
openclaw plugins install npm:openclaw-redacter
```
To install a specific version:
```bash
openclaw plugins install npm:[email protected]
```
### As a local extension
```bash
git clone <repo>
cd openclaw-redacter
npm install
npm run build
```
Then point OpenClaw at the built entry:
```json
{
"extensions": ["/absolute/path/to/openclaw-redacter/dist/index.js"]
}
```
### As a workspace / npm package
Add `@openclaw/redacter` (or your chosen name) to your OpenClaw workspace's
`package.json` and list the package in the OpenClaw extension manifest.
## Recommended starter config
Add this to `~/.openclaw/openclaw.json`:
```jsonc
{
"plugins": {
"redacter": {
"enabled": true,
"mode": "permissive",
// Exact string match — the literal value is redacted wherever it appears.
"exactSecrets": [
"MY_SECRET_TOKEN",
// Environment variable — resolved from process.env at load time.
"${MY_API_KEY}",
// Prefix + secret + suffix pattern.
"example_SECRET_TOKEN_12345",
],
// SHA-256 hash — matches the pre-hashed value, avoids storing raw secrets in config.
"exactSecretHashes": [
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
],
// Built-in detectors (AWS keys, GitHub tokens, JWTs, PEM keys, etc.)
"builtInDetectors": {
"masterEnable": true,
},
// All hooks enabled.
"phases": {
"promptBuild": true,
"beforeAgentRun": true,
"messageFlow": true,
"toolCalls": true,
"persistence": true,
},
// In permissive mode the plugin never blocks — only redacts and warns.
// Switch to "strict" when you're ready to enforce.
"blockOnDetection": {
"criticalPhasesOnly": true,
"allDetections": false,
"detectorClasses": [],
},
"audit": {
"enabled": true,
"includeCountsOnly": false,
"neverLogRawMatches": true,
},
},
},
}
```
Once the config is saved, validate it and restart the gateway:
```bash
openclaw config validate
openclaw gateway restart
```
## Configuration
The plugin reads its config from the OpenClaw plugin config object. The
schema is exported at `dist/config.schema.json`. Defaults favor safety.
```jsonc
{
"plugins": {
"redacter": {
"enabled": true,
"mode": "strict", // "strict" or "permissive"
"exactSecrets": ["MY_INTERNAL_TOKEN"],
// OR reference an environment variable (resolved at load time):
// "exactSecrets": ["${MY_INTERNAL_TOKEN}"],
// OR store hashes to avoid putting raw secrets in config:
"exactSecretHashes": ["<sha256 hex>"],
"regexRules": [
{
"id": "internal_token",
"pattern": "INT_[A-Z0-9]{12}",
"label": "[REDACTED:INTERNAL]",
},
],
"phases": {
"promptBuild": true,
"beforeAgentRun": true,
"messageFlow": true,
"toolCalls": true,
"persistence": true,
},
"blockOnDetection": {
"criticalPhasesOnly": true, // only block in promptBuild / beforeAgentRun
"allDetections": false,
"detectorClasses": [], // empty = all
},
"audit": {
"enabled": true,
"includeCountsOnly": false,
"neverLogRawMatches": true,
},
},
},
}
```
See `src/config.ts` for the full schema.
## Detector management
### Custom regex rules
```jsonc
{
"plugins": {
"redacter": {
"customRegexRules": [
{
"id": "internal_token",
"pattern": "INT_[A-Z0-9]{12}",
"label": "[REDACTED:INTERNAL_TOKEN]",
"flags": "g",
},
],
},
},
}
```
The legacy `regexRules` field is still accepted and is merged with
`customRegexRules` by id (the new field takes precedence on conflict).
### Built-in detector management
```jsonc
{
"plugins": {
"redacter": {
"builtInDetectors": {
"masterEnable": true,
"overrides": {
"anthropicApiKey": {
"enabled": true,
"labelOverride": "[REDACTED:ANT_KEY]",
},
"awsAccessKey": {
"enabled": false,
},
"jwt": {
"patternOverride": "\\beyJ[A-Za-z0-9_\\-]+\\.[A-Za-z0-9_\\-]+\\.[A-Za-z0-9_\\-]+\\b",
},
},
},
},
},
}
```
When `masterEnable` is `false`, all built-in detectors are disabled
unless explicitly re-enabled via a per-detector `enabled: true`. Pattern
overrides are validated at engine construction time; invalid patterns
fall back to the default and surface a warning. Labels follow a layered
resolution: `labelOverride` → `redactLabelsByDetector[id]` → built-in
default.
## Strict vs permissive mode
| Mode | Detections | Blocking |
| ------------ | ---------- | -------------------------------------------------------------------------------------------------------- |
| `strict` | Replace | Block when policy says so (default: only in `promptBuild` / `beforeAgentRun`, or per `detectorClasses`). |
| `permissive` | Replace | Never block; emit warnings, continue. |
In strict mode, blocking behavior is governed by `blockOnDetection`:
- `criticalPhasesOnly: true` (default) — block only in `promptBuild` /
`beforeAgentRun`. Other phases sanitize and warn.
- `allDetections: true` — block on any detection in any phase.
- `detectorClasses: ["exactSecret", "privateKeyPem"]` — block only on
the listed detector classes. If empty, all classes are eligible.
## Hook coverage
| Hook | Purpose | Mutation? | Phase |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ---------------- |
| `before_prompt_build` | Early sanitization of prompt-build inputs. | observation only in v1 | `promptBuild` |
| `before_agent_run` | **Primary final barrier.** Sanitizes prompt/system/messages; returns `InputGateDecision.block` in strict mode on detection. | mutation (block) | `beforeAgentRun` |
| `llm_input` | Post-barrier diagnostic. Emits audit event if a secret still appears in the final LLM payload. | observation | `beforeAgentRun` |
| `before_tool_call` | Sanitizes tool parameters. Optionally blocks in strict mode. | mutation (params / block) | `toolCalls` |
| `after_tool_call` | Observes tool result content; cannot mutate at this hoo
... (truncated)
tools
Comments
Sign in to leave a comment