secretDetectionHook static method
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();
},
);
}