Skip to content

Secret Scanner

SecretScanner detects leaked credentials and secrets in text before they are logged or returned to callers, with optional in-place redaction.

from meshflow.security.secrets import SecretScanner

scanner = SecretScanner(redact=True)
result = scanner.scan("Here is my key: sk-ant-api03-abc123...")
print(result.summary())        # "SECRETS FOUND: 1 match(es) in [api_keys]"
print(result.redacted_text)    # "Here is my key: [REDACTED:api_keys]"

Credential pattern coverage

Eight detection categories covering 30+ named patterns:

Category What is detected
api_keys AWS (AKIA…), GCP (AIza…), GitHub (ghp_/gho_/ghs_/ghr_), Stripe (sk_live_/rk_live_), Twilio, SendGrid (SG.…), Slack (xoxb-/xoxp-), HuggingFace (hf_…), Anthropic (sk-ant-…), OpenAI (sk-…), Cohere, Pinecone, Databricks (dapi…), generic api_key=
tokens JWT (eyJ…), Authorization: Bearer, OAuth refresh/access/session tokens
private_keys RSA, PKCS8, EC, OpenSSH, DSA, PGP PEM blocks
passwords URL-embedded credentials (scheme://user:pass@host), password=, DB_PASS=
database PostgreSQL, MySQL, MongoDB, Redis, MSSQL, JDBC connection strings
cloud Azure storage connection strings and SAS tokens, S3 presigned URLs
certificates X.509 PEM blocks, PKCS12 hints

SecretMatch

@dataclass
class SecretMatch:
    category:     str    # e.g. "api_keys"
    pattern_name: str    # e.g. "anthropic_key"
    matched_text: str    # first 6 chars + "***" — never the full secret
    position:     int    # character offset
    confidence:   float  # 0.70–0.99 (patterns below min_confidence are skipped)
    raw_length:   int    # length of original matched text

SecretScanResult

@dataclass
class SecretScanResult:
    found:         bool
    categories:    list[str]
    matches:       list[SecretMatch]
    redacted_text: str | None  # set when scanner.redact=True

    result.is_clean    # True iff not found
    result.summary()   # "SECRETS FOUND: 2 match(es) in [api_keys, tokens]"

SecretScanner

SecretScanner(
    enabled_categories: list[str] | None = None,  # None = all eight
    min_confidence:     float = 0.70,
    redact:             bool = False,
)
# Quick check
if not scanner.is_clean(text):
    raise ValueError("credential leak detected")

# Full scan
result = scanner.scan(text)
for m in result.matches:
    print(f"{m.pattern_name} at offset {m.position} (confidence {m.confidence:.0%})")

SecretScanGuardrail

Use as a post-generation output guardrail to prevent the LLM from emitting secrets:

from meshflow.security.secrets import SecretScanGuardrail
from meshflow.agents.builder import Agent

agent = Agent(
    name="code-agent",
    role="executor",
    output_guardrails=[
        SecretScanGuardrail(action="block"),   # halt on any secret
        # or: action="modify" to scrub secrets transparently
        # or: action="warn"   to log but pass through
    ],
)
Action Behaviour
"block" passed=False — run is halted before caller receives output
"modify" passed=True with modified_text containing [REDACTED:…] replacements
"warn" passed=True with match metadata attached

When action="modify", the scanner is automatically constructed with redact=True.