Skip to content

FEAT Add RegexScorer and CredentialLeakScorer for regex-based secret detection#1704

Open
francose wants to merge 6 commits into
microsoft:mainfrom
francose:feat/credential-leak-scorer
Open

FEAT Add RegexScorer and CredentialLeakScorer for regex-based secret detection#1704
francose wants to merge 6 commits into
microsoft:mainfrom
francose:feat/credential-leak-scorer

Conversation

@francose
Copy link
Copy Markdown

@francose francose commented May 10, 2026

Closes #1703

Adds two new true/false scorers for fast, regex-based content detection — no LLM call required.

RegexScorer (general purpose)

A reusable TrueFalseScorer that evaluates text against a dict of named regex patterns and returns True if any of them match. Patterns are compiled once in __init__. The score rationale lists which named patterns matched, and categories can be set to tag results (e.g. ["pii"], ["security"]). Aggregator defaults to TrueFalseScoreAggregator.OR but is configurable.

This is intended as a building block for any domain-specific regex check — credentials, PII, profanity, internal identifiers, etc. — without re-implementing the scorer plumbing each time.

CredentialLeakScorer (built on RegexScorer)

Subclasses RegexScorer with a built-in default pattern set covering the most common leaked-credential formats:

  • AWS Access Key IDs and Secret Access Keys
  • GitHub tokens (ghp_ / gho_ / ghu_ / ghs_ / ghr_)
  • Google API keys
  • Slack tokens and webhook URLs
  • JWTs
  • Private key headers (RSA / EC / DSA / OpenSSH)
  • Azure storage keys
  • Connection strings (mongodb, postgres, mysql, redis, amqp)
  • Generic api_key= / secret= / password= / token= assignments

Pass a custom patterns dict to override the defaults entirely (useful for organization-specific secret formats like internal API key prefixes). Category defaults to ["security"].

Because there's no LLM call, scoring runs in microseconds per evaluation, which makes it practical for CI and batch evaluation of thousands of responses.

Other changes

  • Exports both scorers from pyrit.score
  • Adds a Jupytext doc notebook doc/code/scoring/credential_leak_scorer.py walking through detection, clean responses, and custom patterns
  • Unit tests for RegexScorer (match / no-match / multiple matches / category propagation) and CredentialLeakScorer (true positives across all default pattern types, true negatives, rationale content, custom patterns, and memory integration)

Adds a deterministic TrueFalseScorer that detects leaked credentials in
LLM responses using regex pattern matching. Covers AWS keys, GitHub
tokens, Google API keys, Slack tokens/webhooks, JWTs, private key
headers, connection strings, and generic key=value assignments.

Runs without an LLM call, making it suitable for CI pipelines and
high-volume evaluations where the existing SelfAskTrueFalseScorer
with the leakage prompt would be too slow or expensive.

Supports custom pattern dictionaries for domain-specific secret formats.
Copilot AI review requested due to automatic review settings May 10, 2026 16:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new deterministic True/False scorer (CredentialLeakScorer) to quickly detect common credential/secret formats in LLM outputs using compiled regexes, plus unit tests and a public export from pyrit.score.

Changes:

  • Introduces CredentialLeakScorer with a default regex pattern set and optional custom patterns.
  • Adds unit tests covering true positives/negatives, rationale output, custom patterns, and CentralMemory integration.
  • Exposes CredentialLeakScorer from pyrit.score.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
pyrit/score/true_false/credential_leak_scorer.py New regex-based scorer implementation producing true/false Score results with rationale.
tests/unit/score/test_credential_leak_scorer.py Unit tests validating detection behavior, rationale, custom patterns, and memory integration.
pyrit/score/__init__.py Exports CredentialLeakScorer from the public pyrit.score package.

Comment thread pyrit/score/true_false/credential_leak_scorer.py Outdated
Comment thread pyrit/score/true_false/credential_leak_scorer.py Outdated
Comment thread pyrit/score/true_false/credential_leak_scorer.py Outdated
Comment thread tests/unit/score/test_credential_leak_scorer.py Outdated
Comment thread tests/unit/score/test_credential_leak_scorer.py Outdated
Comment thread tests/unit/score/test_credential_leak_scorer.py Outdated
…sive copy, obfuscated test literals

- Replace Optional[X] with X | None per repo style guide
- Use str(detected).lower() for consistent true/false score values
- Copy patterns dict to prevent cross-instance mutation of defaults
- Construct test credential strings via concatenation to avoid secret scanner triggers
@francose
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

- AWS Secret Access Key pattern now requires context (aws_secret_access_key=,
  aws_secret=, or secret_key=) instead of matching any 40-char base64 string.
  Prevents false positives on git commit hashes and random strings.
- Add doc/code/scoring/credential_leak_scorer.py with usage examples for
  default patterns and custom pattern dictionaries.
- Fix AWS test key from 21 to 20 chars to match the AKIA+16 format.
Comment thread pyrit/score/true_false/credential_leak_scorer.py
@francose
Copy link
Copy Markdown
Author

francose commented May 11, 2026

@romanlutz Thank you for the feedback 🙏 — totally agree. The regex matching logic is generic enough to stand on its own.

I'll refactor into:

  • RegexScorer — base class that takes patterns: dict[str, str], compiles them, scores against matches, returns rationale with the matched pattern name
  • CredentialLeakScorer — thin subclass that just passes the default credential patterns to RegexScorer.__init__

That way spinning up new regex-based scorers (PII detection, code patterns, etc.) is just a new subclass with a different pattern set — no engine duplication.

Will push the update.

Extract generic regex matching logic into RegexScorer so future
pattern-based scorers can reuse the engine without class proliferation.
CredentialLeakScorer now passes its default patterns to super().
@francose
Copy link
Copy Markdown
Author

@romanlutz Pushed the refactor! RegexScorer is now the base class and CredentialLeakScorer just passes its default patterns to super. I also added tests for RegexScorer directly and all existing tests still pass. Let me know if this is what you had in mind 🙏

Comment thread pyrit/score/true_false/regex_scorer.py
Comment thread pyrit/score/true_false/credential_leak_scorer.py
Comment thread pyrit/score/true_false/credential_leak_scorer.py Outdated
Copy link
Copy Markdown
Contributor

@romanlutz romanlutz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution! Approving provided the comments are addressed.

@romanlutz romanlutz changed the title Add CredentialLeakScorer for regex-based secret detection FEAT Add RegexScorer and CredentialLeakScorer for regex-based secret detection May 13, 2026
francose and others added 2 commits May 13, 2026 10:43
- RegexScorer raises ValueError when patterns dict is empty
- Connection string pattern now requires user:pass@ credentials,
  so postgres://localhost:5432/mydb no longer triggers a false positive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add regex-based CredentialLeakScorer for fast secret detection

3 participants