Detector request: Supabase secret API keys (sb_secret_)
TruffleHog doesn't detect Supabase's newer secret API keys (sb_secret_...), and I'd like to add a detector for them. Supabase's docs say a secret key gives full access to a project's data and bypasses Row Level Security, so one that ends up in a repo, a frontend bundle or a pasted log exposes the whole project. Supabase is moving projects off the old JWT-based service_role key onto these keys and plans to deprecate the legacy keys by the end of 2026, so more and more of the Supabase secrets out there will be in this format.
What's covered today
The only Supabase detector is supabasetoken, which matches personal access tokens (sbp_ plus 40 characters) and verifies them against the Management API. Nothing matches sb_secret_. The generic JWT detector doesn't cover the legacy service_role key either, because it skips HMAC-signed tokens and those keys are HS256.
The key format
Supabase documents the layout as sb_secret_<22-char random>_<8-char checksum> (API keys, self-hosted key format). Supabase's self-hosting key script (docker/utils/add-new-auth-keys.sh) uses the base64url alphabet for both segments, so - and _ can appear inside the key. That rules out a plain \b at the end of the pattern; I'd require a non-base64url character or end of input after the checksum instead.
Publishable keys (sb_publishable_...) share the layout but are meant to ship in client code, so I'd leave them out on purpose. I'd also skip the fixed secret key the Supabase CLI publishes for local development stacks, since it only works against localhost.
Verification
A secret key doesn't say which project it belongs to, so it can't be verified on its own. My plan:
- Look for a project host (
<ref>.supabase.co, which also catchesdb.<ref>.supabase.co) in the same chunk. - If there is one, call
GET https://<ref>.supabase.co/auth/v1/settingswith the key in theapikeyheader. That endpoint is read-only and only returns the project's public auth settings. 200 means verified, 401 means determinately unverified, and anything else is an indeterminate verification error. - If there's no project host, report the key unverified with no error.
The host is always built from the ref, so the verifier never calls an arbitrary URL found in the scanned data.
Scope, and one question
I'd keep the PR to secret keys. Two things I'd hold for follow-ups unless you'd rather have them in the same PR:
- Legacy
service_roleJWTs. Their payload carries"role":"service_role"and the projectref, so a detector could verify them without needing any extra context. Supabase says they're deprecated by the end of 2026, but plenty of projects still use them. - Checksum validation. In Supabase's self-hosting script the 8-character checksum is a truncated SHA-256 over the project ref and the key body. If the hosted platform uses the same construction, the detector could confirm offline which project a key belongs to before making any call. I haven't been able to confirm that for hosted projects, so I've left it out.
I have a branch ready with the detector, pattern tests (including publishable keys and malformed keys that must not match) and verification tests that run against a local test server, and the tests pass. I'm happy to open the PR if this sounds good to you.
Source: trufflesecurity/trufflehog