Writing a detection pattern is easy. Writing one that finds real credentials without burying the signal in false positives is the hard part, and the only way to know which you have written is to run it against realistic text.
What makes a pattern usable
Anchor to something distinctive. A prefix is the best anchor there is. sk_live_[0-9a-zA-Z]{24,} cannot match a commit SHA. [0-9a-zA-Z]{32} matches thousands of things per repository.
Bound the length. An unbounded + will match far more than you intended and makes the pattern slow. Length bounds also encode real knowledge: GitHub classic tokens are exactly 36 characters after ghp_.
Use a capture group for the value. When the pattern needs context — aws.{0,20}secret.{0,20}['"]([A-Za-z0-9/+=]{40})['"] — capture only the credential so your tooling reports the secret rather than the whole line.
Prefer specific over clever. Ten narrow patterns beat one general one. The general one is what people mute.
The false positive problem
A scanner's real failure mode is not missing a key. It is firing so often that developers stop reading its output, at which point it detects nothing regardless of its patterns.
Test every pattern against text containing commit SHAs, UUIDs, base64-encoded images, minified JavaScript, and lock files. If it fires on any of those, tighten it before shipping it.
Testing both directions
Use the provider key format generator to produce realistic positives, then assemble a negative corpus from the same repository the scanner will run against. A pattern is ready when it catches every positive and none of the negatives.
Catastrophic backtracking
Patterns with nested quantifiers — (a+)+b and its relatives — can take exponential time on inputs that nearly match. In a CI scanner processing large files, that is a hung build. Keep quantifiers flat, prefer character classes over alternation, and bound repetition.
Frequently asked questions
Which flags should I use?
g is required to find every match rather than just the first, and this tool adds it if you omit it. i is usually wrong for credential patterns — key formats are case-sensitive, and ignoring case widens the match for no benefit. m matters only when anchoring with ^ or $ on a multi-line input.
Why does my pattern match too much?
Almost always an unbounded quantifier or a character class that is too wide. [\w-]+ matches most identifiers in a codebase. Add a distinctive prefix and a length bound.
Can I use these patterns in CI?
Yes. The library signatures are the same ones this site's secret leak scanner uses, and they are written to be portable to grep, ripgrep and most scanning tools. Watch for engine differences — Go's RE2, used by several scanners, does not support lookahead.
How do I match a key with no prefix?
You need context instead. Match the surrounding assignment: the variable name, the colon or equals, the quote, then capture the value. That is how the AWS secret access key pattern in the library works.