Secrets detection
What we look for
The pattern library covers six broad categories:
| Category | Examples |
|---|---|
| Cloud credentials | AWS access keys, GCP service account keys, Azure SAS tokens, Scaleway secret keys |
| SaaS tokens | GitHub PATs, GitLab tokens, Stripe keys, Slack tokens, OpenAI API keys |
| Database connection strings | postgres://, mysql://, mongodb+srv:// with credentials embedded |
| Cryptographic material | PEM private keys, SSH private keys, JWT secrets |
| Generic high-entropy | Long base64/hex strings near the words "secret", "token", "key" |
| Webhook URLs | Slack incoming webhooks, Discord webhooks |
Each pattern has a confidence level (HIGH, MEDIUM, LOW). Patterns that match a
unique vendor format (AWS keys start with AKIA, Stripe with sk_live_) are HIGH;
generic high-entropy patterns are LOW.
Where we scan
| Source | Scope |
|---|---|
| Object storage | Sample first N MB of each object, scan for patterns |
| Block volumes | Mount snapshot read-only, walk filesystems |
| Container images | Layer by layer |
| Databases | Sampled rows from text columns |
| IaC repos | Every file, on every push and PR |
| Serverless functions | Source code + environment variables |
You can scope each pattern to specific source types via Settings → Policies → Secrets (e.g. only scan IaC for GitHub PATs, not buckets).
Validation, the differentiator
A finding without validation is just a regex hit. The pattern matched something that looks like an AWS key, but is it real? Is it still active?
For high-confidence patterns, Ctadel optionally calls the vendor's identity endpoint with the candidate secret to determine its validity:
| Validity | Meaning |
|---|---|
VALID | The secret was successfully used to authenticate. Treat as a live breach. |
INVALID | The vendor rejected the secret. Probably a leftover or rotated value. |
UNKNOWN | We can't validate (no vendor endpoint, or validation disabled). Triage manually. |
Validation is read-only and uses the least-privileged introspection endpoint each
vendor exposes (e.g. AWS STS GetCallerIdentity, GitHub /user).
You can disable validation per pattern if your security policy forbids it.
What ends up in a Secret finding
| Field | Example |
|---|---|
| Rule key | aws_access_key |
| Resource ID | The bucket / volume / image / repo holding the secret |
| File path | s3://prod-data-eu/legacy/config.yml |
| Snippet | aws_access_key_id: AKIA****PROD (redacted) |
| Validity | VALID / INVALID / UNKNOWN |
| Risk score | Composite of severity × validity × exposure (0–100) |
The full secret value is never stored in Ctadel. Only a hash and a redacted snippet.
What's next
- The Secrets module
- DSPM, sibling detector for sensitive data