KeyDrift
Free scan
The Secret Leak Field Manual

2 · The key-class catalog

The Secret Leak Field Manual · 7 min read

Question this chapter answers: Given a specific string, what does possessing it actually let someone do?

Severity is not about how "secret-looking" a string is. It is the combination of three things: scope (what one credential can reach), durability (how long it works), and visibility (where it can be read from). A publishable key is safe in every browser precisely because its scope is designed for that. A database connection string is critical anywhere because it is the database. This chapter is the reference catalog: six families, one table each, and a plain statement of what possession means for every credential type.

Every example below is synthetic, marked with embedded FAKE strings, and safe to read aloud. The full format reference is Appendix B.

Family 1 — Payments

CredentialAnatomyScope modelWhat possession means
Publishable pk_live_…Prefix + random body; e.g. pk_live_FAKE000000000000000000000Token identification onlyNothing sensitive; it belongs in browsers
Secret sk_live_…Prefix + random body; e.g. sk_live_FAKE000000000000000000000Unrestricted account accessCharges, refunds, customer records, payout destinations — full control of the payment operation
Restricted rk_live_…Same shape as secret keys; e.g. rk_live_FAKE000000000000000000000Permissions you assign per keyOnly the granted permissions — real but bounded damage
Webhook signing secret whsec_…e.g. whsec_FAKE000000000000000000000000Authenticates events to your endpointAbility to forge events your server accepts as genuine — fake fulfillment triggers, false subscription states

Stripe documents that restricted keys exist to limit damage if obtained, recommends migrating new use cases away from unrestricted secret keys, and now adds organization-level keys to the same family (docs.stripe.com/keys). One attribution note: Clerk issues secret keys in exactly Stripe's shape. When you find an sk_live_-shaped string, confirm which provider it belongs to before acting — the rotation path differs even though the blast radius is similar.

Family 2 — Cloud

CredentialAnatomyScope modelWhat possession means
AWS long-lived pairAccess key ID + secret, e.g. AKIAFAKEEXAMPLE000000 / FAKE0000000000000000000000000000000000Whatever IAM attaches to that userProgrammatic AWS access under that identity until deleted
AWS temporary (STS)ASIA… IDs with session tokensTime-boxed, role-scopedFull role access while valid — expiry is not a response plan
Google service-account JSONPEM private key inside JSON; e.g. -----BEGIN PRIVATE KEY-----\nFAKE000000...\n-----END PRIVATE KEY-----Service-account roles across projectsImpersonation of that service account's grants

AWS caps users at two active access keys per person specifically so rotation never requires downtime, and its own guidance prefers short-lived credentials over long-term keys (IAM user guide). Firebase web keys (AIza…) are the family's deliberate exception: they are public by design, protected by configuration — API restrictions and app checks — rather than secrecy (Firebase docs). Reporting an AIza key as a leaked secret is a false positive; reporting it without restrictions configured is a finding worth fixing.

Family 3 — Database and backend-as-a-service

CredentialAnatomyScope modelWhat possession means
Postgres URLpostgresql://app:FAKEPASSWORD@db.example.internal:5432/prodThe database role named in the URLDirect database access, bypassing every application-layer check
MongoDB URLmongodb+srv://app:FAKEPASSWORD@cluster0.example.mongodb.net/prodThe database user in the stringSame — the connection string is the login
Supabase service_role JWTThree-part JWT; synthetic: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJzZXJ2aWNlX3JvbGUiLCJpYXQiOjE3NTQwMDAwMDB9.FAKE_SIGNATURE_EXAMPLE_ONLYBypasses Row Level Security entirelyRead, write, delete on all project data
Supabase sb_secret_…New-format platform keyFull data access, replaces legacy JWTsSame elevated access, individually revocable
Supabase management token (sbp_…)Account-level tokenManages projects via the management APIControl over projects, not just data

Supabase's current guidance: publishable keys (sb_publishable_…) are safe to expose; secret keys belong only in backend components; the legacy JWT-based anon and service_role keys are deprecated by the end of 2026 (API keys guide). Two recognition notes prevent expensive mistakes. First, local development mints the same service_role JWT on every machine, identified by its issuer; it grants nothing hosted and is not a leak. Second, the anon key is public by design — confusing it with service_role is the most common misclassification in this family.

Family 4 — Language models

CredentialAnatomyScope modelWhat possession means
OpenAI project keysk-proj-FAKE000000000000000000000000Scoped to a projectBillable API access under that project's limits
OpenAI admin keysk-admin-… shapeOrganization-wide managementBroadest LLM exposure class
OpenAI-compatible legacy shapesk-FAKE0000000000000000000000000000Provider-specificBillable access at DeepSeek, Groq, Together, Fireworks, and others sharing the shape
Anthropicsk-ant-api03-FAKE0000000000000000000000000000000000000000000000Console/workspace-scopedBillable API access

Possession means spending your money and quota. There is no sandbox mode for production LLM keys: treat every one as live. OpenAI's help center states the recovery path plainly — a lost or exposed key cannot be retrieved, so create a new one and update the application (help.openai.com). Project-scoped keys with spend limits are the blast-radius tool here; Chapter 6 applies them.

Family 5 — Source control

CredentialAnatomyScope modelWhat possession means
GitHub classic PATghp_, gho_, ghu_, ghs_, ghr_ prefixes; e.g. ghp_FAKE0000000000000000000000000000000Scopes layered on top of everything the owning user can reachRepo contents, code, org administration — bounded by scopes, unbounded by repo count
Fine-grained PATgithub_pat_FAKE000000000000000000_0000000000000000000000000000000One owner, selected repos, granular permissionsOnly the granted permissions on the chosen repositories

GitHub's documentation treats tokens like passwords, recommends fine-grained tokens over classic, and supports organization policies requiring approval and maximum lifetimes (managing personal access tokens). GitHub also operates secret scanning on public repositories and works with partners so certain detected tokens are revoked automatically (about secret scanning) — a safety net that covers GitHub's own token formats, not the other five families in this chapter.

Family 6 — Email, SMS, and messaging

CredentialAnatomyScope modelWhat possession means
SendGridSG.FAKE0000000000000000000.0000000000000000000000000000000000000Full-access or scoped keysSend email as your domain — the raw material of phishing campaigns wearing your brand
Resendre_FAKE_000000000000000000000Account-scoped sendingSame sending capability
Slack bot/user/app tokensxoxb-0000-FAKE000000000000000 and siblingsBot: installed workspace scope; user: acting user; app-level: cross-workspace app actionsMessage posting, channel reads, workspace actions per scope
Mapbox secret tokensk.eyJFAKE0000000000000000.FAKE0000000000000000Account operations incl. token managementBilling-relevant account changes; only pk. tokens belong in browsers (Mapbox tokens)

Email credentials are underrated in severity rankings because the direct financial drain is invisible next to a payment key. The damage arrives later: your domain sends spam or phishing, deliverability collapses, and reputation repair takes weeks.

Reading the tables under pressure

When someone hands you an unknown string mid-incident:

  1. Match the prefix or anatomy against Appendix B → identify family.
  2. Take the "what possession means" row literally → assume capability, verify with logs (Chapter 5).
  3. If two providers share a shape (Stripe/Clerk, OpenAI/gateways) → attribute honestly before rotating, then rotate regardless.

Do this now

  • [ ] Build your inventory against these six families; note which families you hold zero, one, or many of.
  • [ ] Mark every credential in your inventory as full-scope or scoped; scoped-only inventories rotate faster and cheaper.
  • [ ] Confirm no Mapbox secret token and no Supabase service_role/sb_secret_ value exists in any browser-facing code.
  • [ ] For each family you use, open the provider's cited documentation once now — reading docs during an incident costs minutes you will not have.