secretDetectionHook static method

HookRegistration secretDetectionHook({
  1. void onWarning(
    1. String warning
    )?,
})

Hook that scans content for potential secrets and sensitive data.

Checks tool inputs and outputs for patterns that look like API keys, passwords, tokens, and other secrets.

Implementation

static HookRegistration secretDetectionHook({
  void Function(String warning)? onWarning,
}) {
  // Common patterns for secrets
  final secretPatterns = [
    RegExp(r'(?:api[_-]?key|apikey)\s*[=:]\s*\S+', caseSensitive: false),
    RegExp(r'(?:password|passwd|pwd)\s*[=:]\s*\S+', caseSensitive: false),
    RegExp(r'(?:secret|token)\s*[=:]\s*\S+', caseSensitive: false),
    RegExp(
      r'(?:access[_-]?key|aws[_-]?key)\s*[=:]\s*\S+',
      caseSensitive: false,
    ),
    RegExp(r'-----BEGIN (?:RSA |DSA |EC )?PRIVATE KEY-----'),
    RegExp(r'sk-[a-zA-Z0-9]{20,}'), // OpenAI-style keys
    RegExp(r'ghp_[a-zA-Z0-9]{36}'), // GitHub personal access tokens
    RegExp(r'(?:Bearer|Basic)\s+[a-zA-Z0-9+/=._-]{20,}'),
  ];

  return HookRegistration(
    id: 'builtin:secret-detection',
    type: HookType.preToolExecution,
    priority: HookPriority.high,
    name: 'Secret Detection',
    description: 'Warns about potential secrets in content.',
    source: 'builtin',
    tags: {'security', 'secrets'},
    handler: (context) {
      if (context is! ToolHookContext) return const HookContinue();

      final inputStr = context.toolInput.toString();

      for (final pattern in secretPatterns) {
        if (pattern.hasMatch(inputStr)) {
          final warning =
              'Potential secret detected in tool input for '
              '"${context.toolName}". Pattern: ${pattern.pattern}';
          onWarning?.call(warning);
          return HookContinue(modifiedData: {'secretWarning': warning});
        }
      }

      return const HookContinue();
    },
  );
}