Feature: Automatic detection and redaction of secrets in prompts/observations #191

Closed
opened 2026-01-24 11:24:18 +00:00 by jack · 0 comments
Owner

Beschreibung

Aktuell werden Prompts und Tool-Outputs unverändert gespeichert und in CLAUDE.md geschrieben. Wenn ein User versehentlich Passwörter, API-Keys oder andere sensible Daten im Prompt hat, werden diese persistiert.

Risiken

  1. Passwörter in der Datenbank: Werden in user_prompts und observations gespeichert
  2. Secrets in CLAUDE.md: Könnten ins Git-Repository committed werden
  3. UI-Anzeige: Werden in Memories-View und Live-View angezeigt

Zu erkennen

Patterns (Regex-basiert)

const SECRET_PATTERNS = [
  // API Keys
  /sk-[a-zA-Z0-9]{32,}/g,                    // OpenAI
  /sk-ant-[a-zA-Z0-9-]{32,}/g,               // Anthropic
  /[a-zA-Z0-9]{32}/g,                        // Generic 32-char keys
  
  // AWS
  /AKIA[0-9A-Z]{16}/g,                       // AWS Access Key
  /aws_secret_access_key\s*=\s*\S+/gi,
  
  // GitHub/GitLab
  /ghp_[a-zA-Z0-9]{36}/g,                    // GitHub PAT
  /glpat-[a-zA-Z0-9-]{20}/g,                 // GitLab PAT
  
  // Passwords
  /password\s*[:=]\s*["']?[^\s"']+["']?/gi,
  /passwd\s*[:=]\s*["']?[^\s"']+["']?/gi,
  /secret\s*[:=]\s*["']?[^\s"']+["']?/gi,
  
  // Connection Strings
  /mongodb(\+srv)?:\/\/[^:]+:[^@]+@/gi,
  /postgres(ql)?:\/\/[^:]+:[^@]+@/gi,
  /mysql:\/\/[^:]+:[^@]+@/gi,
  
  // Private Keys
  /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,
  
  // JWT
  /eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*/g,
  
  // .env patterns
  /[A-Z_]+_API_KEY\s*=\s*\S+/g,
  /[A-Z_]+_SECRET\s*=\s*\S+/g,
  /[A-Z_]+_TOKEN\s*=\s*\S+/g,
];

Entropy-basiert

Hochentropische Strings (base64, hex) können auf Secrets hindeuten:

function hasHighEntropy(str: string, threshold = 4.5): boolean {
  // Shannon entropy calculation
  const freq = new Map<string, number>();
  for (const char of str) {
    freq.set(char, (freq.get(char) || 0) + 1);
  }
  let entropy = 0;
  for (const count of freq.values()) {
    const p = count / str.length;
    entropy -= p * Math.log2(p);
  }
  return entropy > threshold;
}

Implementierung

Option A: Redaction (Ersetzen)

function redactSecrets(text: string): string {
  let redacted = text;
  for (const pattern of SECRET_PATTERNS) {
    redacted = redacted.replace(pattern, '[REDACTED]');
  }
  return redacted;
}

// Vor dem Speichern
const safePrompt = redactSecrets(userPrompt);
const safeOutput = redactSecrets(toolOutput);

Option B: Warnung ohne Speicherung

function detectSecrets(text: string): SecretMatch[] {
  const matches: SecretMatch[] = [];
  for (const pattern of SECRET_PATTERNS) {
    const found = text.match(pattern);
    if (found) {
      matches.push({ pattern: pattern.source, count: found.length });
    }
  }
  return matches;
}

// Bei Erkennung: Observation nicht speichern, Warnung loggen
if (detectSecrets(toolOutput).length > 0) {
  logger.warn('Secrets detected in output, skipping observation');
  return;
}

Option C: Konfigurierbar

// settings.json
{
  "SECRET_DETECTION_ENABLED": true,
  "SECRET_DETECTION_MODE": "redact", // "redact" | "skip" | "warn"
  "SECRET_DETECTION_PATTERNS": [...] // Custom patterns
}

Stellen für Integration

  1. session-service.ts: Bei recordPrompt() und queueObservation()
  2. post-tool-use.ts: Vor dem Senden an Backend
  3. claude-md-handler.ts: Vor dem Schreiben der CLAUDE.md
  4. UI: Warnung anzeigen wenn Secrets erkannt wurden

Zusätzliche Features

  • Audit-Log: Erkannte Secrets loggen (ohne Inhalt) für Security-Review
  • User-Warnung: Toast/Notification in UI wenn Secret erkannt
  • Whitelist: Bestimmte Patterns ignorieren (z.B. Test-Keys)
  • False-Positive-Handling: Manuelles Markieren als "kein Secret"

Betroffene Dateien

  • Neue Utility: packages/shared/src/secret-detector.ts
  • packages/backend/src/services/session-service.ts
  • packages/hooks/src/handlers/post-tool-use.ts
  • packages/worker/src/handlers/claude-md-handler.ts

Priorität

Hoch - Sicherheitsrelevantes Feature

## Beschreibung Aktuell werden Prompts und Tool-Outputs unverändert gespeichert und in CLAUDE.md geschrieben. Wenn ein User versehentlich Passwörter, API-Keys oder andere sensible Daten im Prompt hat, werden diese persistiert. ## Risiken 1. **Passwörter in der Datenbank**: Werden in `user_prompts` und `observations` gespeichert 2. **Secrets in CLAUDE.md**: Könnten ins Git-Repository committed werden 3. **UI-Anzeige**: Werden in Memories-View und Live-View angezeigt ## Zu erkennen ### Patterns (Regex-basiert) ```typescript const SECRET_PATTERNS = [ // API Keys /sk-[a-zA-Z0-9]{32,}/g, // OpenAI /sk-ant-[a-zA-Z0-9-]{32,}/g, // Anthropic /[a-zA-Z0-9]{32}/g, // Generic 32-char keys // AWS /AKIA[0-9A-Z]{16}/g, // AWS Access Key /aws_secret_access_key\s*=\s*\S+/gi, // GitHub/GitLab /ghp_[a-zA-Z0-9]{36}/g, // GitHub PAT /glpat-[a-zA-Z0-9-]{20}/g, // GitLab PAT // Passwords /password\s*[:=]\s*["']?[^\s"']+["']?/gi, /passwd\s*[:=]\s*["']?[^\s"']+["']?/gi, /secret\s*[:=]\s*["']?[^\s"']+["']?/gi, // Connection Strings /mongodb(\+srv)?:\/\/[^:]+:[^@]+@/gi, /postgres(ql)?:\/\/[^:]+:[^@]+@/gi, /mysql:\/\/[^:]+:[^@]+@/gi, // Private Keys /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g, // JWT /eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*/g, // .env patterns /[A-Z_]+_API_KEY\s*=\s*\S+/g, /[A-Z_]+_SECRET\s*=\s*\S+/g, /[A-Z_]+_TOKEN\s*=\s*\S+/g, ]; ``` ### Entropy-basiert Hochentropische Strings (base64, hex) können auf Secrets hindeuten: ```typescript function hasHighEntropy(str: string, threshold = 4.5): boolean { // Shannon entropy calculation const freq = new Map<string, number>(); for (const char of str) { freq.set(char, (freq.get(char) || 0) + 1); } let entropy = 0; for (const count of freq.values()) { const p = count / str.length; entropy -= p * Math.log2(p); } return entropy > threshold; } ``` ## Implementierung ### Option A: Redaction (Ersetzen) ```typescript function redactSecrets(text: string): string { let redacted = text; for (const pattern of SECRET_PATTERNS) { redacted = redacted.replace(pattern, '[REDACTED]'); } return redacted; } // Vor dem Speichern const safePrompt = redactSecrets(userPrompt); const safeOutput = redactSecrets(toolOutput); ``` ### Option B: Warnung ohne Speicherung ```typescript function detectSecrets(text: string): SecretMatch[] { const matches: SecretMatch[] = []; for (const pattern of SECRET_PATTERNS) { const found = text.match(pattern); if (found) { matches.push({ pattern: pattern.source, count: found.length }); } } return matches; } // Bei Erkennung: Observation nicht speichern, Warnung loggen if (detectSecrets(toolOutput).length > 0) { logger.warn('Secrets detected in output, skipping observation'); return; } ``` ### Option C: Konfigurierbar ```json // settings.json { "SECRET_DETECTION_ENABLED": true, "SECRET_DETECTION_MODE": "redact", // "redact" | "skip" | "warn" "SECRET_DETECTION_PATTERNS": [...] // Custom patterns } ``` ## Stellen für Integration 1. **`session-service.ts`**: Bei `recordPrompt()` und `queueObservation()` 2. **`post-tool-use.ts`**: Vor dem Senden an Backend 3. **`claude-md-handler.ts`**: Vor dem Schreiben der CLAUDE.md 4. **UI**: Warnung anzeigen wenn Secrets erkannt wurden ## Zusätzliche Features - **Audit-Log**: Erkannte Secrets loggen (ohne Inhalt) für Security-Review - **User-Warnung**: Toast/Notification in UI wenn Secret erkannt - **Whitelist**: Bestimmte Patterns ignorieren (z.B. Test-Keys) - **False-Positive-Handling**: Manuelles Markieren als "kein Secret" ## Betroffene Dateien - Neue Utility: `packages/shared/src/secret-detector.ts` - `packages/backend/src/services/session-service.ts` - `packages/hooks/src/handlers/post-tool-use.ts` - `packages/worker/src/handlers/claude-md-handler.ts` ## Priorität Hoch - Sicherheitsrelevantes Feature
jack closed this issue 2026-01-24 17:40:13 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
customable/claude-mem#191
No description provided.