Secret handling
Gate reads files full of credentials and prints a report about them. Getting this wrong would mean the security scanner caused the incident it was looking for.
The invariant
Nothing downstream of an adapter ever holds a raw credential.
Adapters read raw bytes from disk. In the same step, they detect credential material, classify it, and replace it with a placeholder. Everything after that point (rules, blast radius, terminal output, JSON, baselines, telemetry) works with classifications and never with values.
This is structural, not a matter of care. There is no code path where a rule could print a secret, because no rule ever receives one.
Two independent checks back it up:
gate scan --jsonre-scans its own output for credential shapes and refuses to emit anything that matches.- Gate's test suite scans every rendering of every fixture (terminal, JSON, SARIF, one-line) and asserts nothing leaks.
What Gate detects
Shape detectors: the value alone is enough to be confident, because the issuer gave it a distinctive prefix:
GitHub tokens (ghp_, gho_, ghs_, github_pat_), AWS access key IDs,
Google API keys, OpenAI and Anthropic keys, Slack tokens and webhooks, Stripe
secret keys, npm tokens, GitLab PATs, SendGrid keys, Hugging Face tokens,
private key blocks, JWTs, database URLs containing a password, HTTP Basic
credentials, and bearer tokens.
Contextual detection: a secret-shaped value in a secret-named field. This
needs both a suspicious name (api_key, GITHUB_TOKEN, DATABASE_URL,
client_secret) and a value that survives placeholder, reference, length and
entropy checks.
Gate looks for credentials in env, in args, in headers, and in the URL
itself, including https://token@host and ?api_key=.
What redaction looks like
GATE001 CRITICAL
Hardcoded credential in agent configuration.
github has a literal credential in GITHUB_PERSONAL_ACCESS_TOKEN.
Rotate it and replace it with an environment reference.
File: .mcp.json
Field: mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN
Type: github-token
Value: [REDACTED]
The field name is kept, because names are not secrets and the name is how you find the thing. The value is never shown.
Where Gate needs to distinguish two secrets, the same token in two files versus two different tokens, it uses a short salted one-way digest:
[REDACTED github-token #a3f1e2]
Six hex characters of HMAC-SHA256 over a fixed application salt. Enough to compare; nothing to recover.
Why no last four characters
Showing the last four characters of a credential is the industry convention. Gate does not do it.
Four characters of a real token is still four characters of a real token. It narrows a brute-force search, it confirms a guess, and it ends up in public CI logs. The digest gives you the same practical benefit, telling secrets apart, with nothing recoverable.
This costs a little convenience. It is the correct trade for a tool whose whole promise is that running it is never how a secret leaks.
Avoiding false positives
A developer who sees Gate scream about a placeholder stops reading Gate's output. Detection is conservative.
References are not findings. ${env:GITHUB_TOKEN}, $GITHUB_TOKEN,
%TOKEN%, {{ token }} and op://vault/item/field are all recorded as
credentials the agent holds, and none of them is reported as a leak. Referencing
a secret is the fix, not the problem.
Authorization: Bearer ${env:VENDOR_TOKEN}, a value that merely contains an
interpolation, is likewise never treated as a literal.
Placeholders are not findings. ghp_xxxxxxxx..., your-token-here,
CHANGEME, <YOUR_API_KEY>, and any token whose body has too little entropy
to be real.
Entropy and shape gates. An unrecognised value in a secret-named field needs
at least 12 characters, no whitespace, and Shannon entropy above 3.0 bits per
character before Gate will call it a credential. Paths and plain URLs in
*_path and *_url fields are configuration, not keys.
If Gate ever leaks
Report it. That is the highest-severity bug class in this project.
Do not attach the output. Describe the shape of the configuration that triggered it. See responsible disclosure, including the promise that Gate will never ask you for a real credential to reproduce a bug.