HookStackGitHub
Back to catalogue
SecurityMessageDisplay

Redact secrets from displayed output

Intercepts assistant message text as it streams to the screen and replaces patterns matching API keys, GitHub tokens and Bearer credentials with [REDACTED] placeholders. The transcript and model context retain the original text; only the rendered display is sanitized.

Use cases

  • Prevent API keys from being visible on screen during pair programming or screen shares
  • Sanitize assistant output that echoes back tool results containing credentials
  • Compliance screen recording: ensure no secrets appear in recorded sessions

Providers & tags

Claude Code
#security#redaction#secrets#display#compliance

settings.json fragment

{
  "hooks": {
    "MessageDisplay": [
      {
        "hooks": [
          {
            "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/message-display-redact-secrets.mjs",
            "type": "command"
          }
        ]
      }
    ]
  }
}

Script · .claude/hooks/message-display-redact-secrets.mjs

#!/usr/bin/env node
// Caviarde les secrets dans le contenu affiché (MessageDisplay)
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';

export function run(input) {
  const delta = input.delta ?? '';

  const redacted = delta
    .replace(/sk-(?:ant-api03-|proj-)[A-Za-z0-9_-]{20,}/g, '[REDACTED-ANTHROPIC-KEY]')
    .replace(/sk-[A-Za-z0-9]{20,}/g, '[REDACTED-API-KEY]')
    .replace(/ghp_[A-Za-z0-9]{36}/g, '[REDACTED-GH-TOKEN]')
    .replace(/ghs_[A-Za-z0-9]{36}/g, '[REDACTED-GH-TOKEN]')
    .replace(/Bearer [A-Za-z0-9_\-.]{20,}/g, 'Bearer [REDACTED]');

  if (redacted === delta) return null;
  return {
    hookSpecificOutput: {
      hookEventName: 'MessageDisplay',
      displayContent: redacted,
    },
  };
}

/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  const input = JSON.parse(readFileSync(0, 'utf8'));
  const result = run(input);
  if (result) process.stdout.write(JSON.stringify(result));
}