KeyDrift
Free scan
The Secret Leak Field Manual

3 · Blast-radius assessment

The Secret Leak Field Manual · 4 min read

Question this chapter answers: A key has leaked — how much can it hurt, and how fast can you know?

Assessment is the step teams skip under pressure, and skipping it is expensive in both directions. Assess too little and you rotate a publishable key at 2 a.m. while the real leak keeps shipping. Assess nothing and you discover three days later that the key reached a production database. The method below takes minutes, not hours, and it produces a written rating your whole response can hang on.

The five questions

1. Which key exactly? Class and scope from Chapter 2's tables. rk_live_ with only read permissions is a different incident from sk_live_. An ASIA temporary key is different again — short-lived by design, but full-role while valid.

2. Where did it land? Map to the Chapter 1 surfaces and ask who can read that surface. A key in a private build log has one audience; the same key in a public bundle has every visitor and every crawler.

3. How long has it been exposed? Three clocks run at once: credential age (provider shows creation date), first presence on the surface (git blame for source; deploy history for bundles; log retention for CI), and time since discovery. Long dwell changes the audit burden in Chapter 5 even when rotation goes perfectly.

4. What does usage show? Every major provider records requests per credential. Where each family logs is Chapter 5's table; for assessment, one question matters: does usage show activity you cannot attribute?

5. What sits behind it? Scope tells you what the credential could touch; you need what it actually guards. For a database URL: which environment, which tables, does it bypass application checks? For a cloud pair: which roles, which buckets, which billing surface?

The worksheet

Fill it in before touching anything except containment (Chapter 4 starts containment immediately for critical classes — assessment runs in parallel).

FieldEntry
Key class / provider
Masked value + fingerprintFirst 8 + last 4 characters only; never the full value
Surface(s) found onCh. 1 row numbers
Readable byPrivate team / org / public internet
Credential createdDate from provider console
First exposed (best estimate)Commit date / deploy date / log window
Usage anomaliesYes / no / unknown — where checked
Data or systems behind itEnvironments, tables, roles, spend limits
RatingCritical / high / medium + one sentence why

The severity rubric

RatingDefinitionTypical members
CriticalFull or bypass-level access to data, infrastructure, money movement, or trusted sendingDatabase URLs, Supabase service_role/sb_secret_, Stripe secret keys, AWS pairs, OpenAI admin keys, PEM private keys, GitHub PATs with broad scopes
HighMeaningful access bounded by configuration, or trusted-identity abuseRestricted payment keys, scoped LLM keys without caps, SendGrid/Resend/Slack tokens, webhook signing secrets, GitHub tokens limited to selected repos
MediumNo direct access or no real funds at stakeTest-mode keys against sandbox data, public-by-design credentials missing their restrictions, expired JWTs

Two calibration notes. Test-mode payment keys are medium, not zero — they pollute sandboxes and normalize sloppiness, but no customer funds move. And a public-by-design key (Firebase AIza, Supabase anon) is not a finding at all unless its protective configuration is missing; then the fix is the restriction, not rotation theater.

Worked walkthrough

A scanner finds an rk_live_-shaped string in the JavaScript of a marketing site. Synthetic example of the kind: rk_live_FAKE000000000000000000000.

  1. Which key: restricted Stripe key, live mode. Check attribution first — Clerk issues keys in this shape, so confirm in the Stripe dashboard whether a matching restricted key exists there.
  2. Where: surface 4, a public browser bundle → readable by everyone.
  3. How long: deploy history shows the bundle shipped eleven days ago; the key was created last quarter.
  4. Usage: Stripe's per-key request logs (Dashboard → API keys → overflow menu → View request logs) show reads of recent charges from two unfamiliar networks. Assessment now includes "evidence of use."
  5. Behind it: permissions were set to charges:read and customers:read during a dashboard experiment. No write, no refund capability.

Rating: high — bounded capability, public exposure, eleven-day dwell, evidence of use. That rating drives the response order in Chapters 4–6: immediate rotation with Stripe's dual-validity window, a usage audit over the full dwell period, and disclosure judgment reserved because the reachable data was read-only customer metadata rather than card data.

The same walkthrough with sk_live_ instead of rk_live_ rates critical at step 1, and steps 2–5 refine the response rather than delay it.

Do this now

  • [ ] Save the worksheet as a template (Appendix C extends it into a full incident record).
  • [ ] Write your organization's rule for who may rate an incident critical — decide now, not mid-incident.
  • [ ] Locate the per-key request-log view for every provider you use; bookmark each.
  • [ ] Run one assessment drill: pick any key in your inventory and fill the worksheet in under ten minutes, using masked values throughout.