A field guide to credential prefixes
The credential formats you will find in a JavaScript bundle — what each prefix means, what it grants, and whether it belongs in a browser at all.
You have found a long string in your deployed JavaScript. This page tells you what it is.
Entries are grouped by issuer rather than by severity, because that is how you will search when you have a string in front of you. Every example body below is fabricated. The useful question is never "is there a key in the bundle" — there almost certainly is, and several of them are meant to be there. It is "is there a key in the bundle that grants more than a stranger should have".
The formats
sb_secret_
Supabase secret key, in the format introduced with their 2024 key scheme. Full database access, bypassing every row-level security policy in the project. Unlike the older JWT format there is no payload to inspect — the prefix alone is the claim. Never belongs in a browser. Revoke in the Supabase dashboard under API keys.
sb_publishable_
Supabase publishable key, the browser-facing half of the same scheme and the replacement for the anon key. Designed to be public; access through it is constrained by your policies. Belongs in a browser. Finding one is informational, not a leak — and if it worries you, the thing to check is not the key but whether RLS is enabled on your tables.
sbp_
Supabase personal access token, for the management API. This is an account-level credential rather than a project one: it reaches every project the owner can see, including creating and deleting them. Never belongs in a browser, never belongs in CI without scoping, and the blast radius is larger than people expect.
sk_live_ and sk_test_
Stripe secret key. Full API access — create charges, issue refunds, read your customer list, list payouts. sk_test_ is reported at lower severity because no real money can move through it, but it still exposes your test data and your integration shape.
One caveat worth knowing: Clerk issues secret keys in exactly this format, and nothing in the string distinguishes them. Attribution depends on what else appears nearby in the code. If you find one, check which provider your surrounding code is talking to before you rotate the wrong thing.
sk_live_EXAMPLEONLY000000000000000000
rk_live_ and rk_test_
Stripe restricted key. What it reaches depends entirely on the permissions granted when it was created, which is rarely obvious from the string and frequently forgotten by whoever created it. Treat as sensitive until you have opened the dashboard and read its actual scope. Not browser-safe.
pk_live_ and pk_test_
Stripe publishable key. Designed for the browser; it can tokenise payment details and nothing else. It cannot read a customer, cannot charge a card and cannot issue a refund. Belongs in a browser, and reporting it as a leak is the kind of false positive that teaches people to ignore their tooling.
whsec_
Webhook signing secret. Not an API key, which is precisely why it gets overlooked and almost never rotated — but it is the only thing standing between your endpoint and forged events. Someone holding it can sign a payload that your handler will accept as genuine, marking an order paid or provisioning an account. Never belongs in a browser.
sk-proj-, sk-admin-, sk-svcacct-
OpenAI API keys in the modern formats: project, admin and service-account respectively. All three spend money against your account. The admin key is the worst of them, reaching organisation-level operations rather than a single project. Never browser-safe — if your frontend calls a model provider directly, the credential is public and the bill is yours.
sk- followed by 32 or more characters
An OpenAI-compatible API key, and the name matters. This older format is issued by a long list of providers whose APIs mirror OpenAI's, and the string carries nothing identifying which one. Assume it spends money somewhere and find out where before rotating. Never browser-safe.
sk-ant-api and sk-ant-admin
Anthropic API key, with a version segment after the prefix. Same category as above: it spends money against your account, and the admin variant reaches organisation settings. Never browser-safe.
AKIA and ASIA
AWS access key IDs. AKIA is a long-lived IAM credential and ASIA is a temporary STS credential that expires on its own, which is why the second is treated slightly less severely — but "expires eventually" is not a control on the timescale that matters here.
What either one grants is whatever its IAM policy grants, which in practice is usually far more than the one operation it was added for. Never browser-safe. If you needed browser uploads, presigned URLs are the answer.
AKIAEXAMPLE000000000
AIza
Google API key, and the most common false positive in off-the-shelf scanners. Firebase web configurations are designed to ship this to the browser — access is controlled by Firebase Security Rules and by key referrer restrictions, not by keeping the string secret. Google's own documentation publishes one. Belongs in a browser; what to check is your Security Rules and your key restrictions, not the key's presence.
ghp_, gho_, ghu_, ghs_ and ghr_
GitHub tokens in the classic formats: personal, OAuth, user-to-server, server-to-server and refresh. A classic personal access token typically carries every private repository the user can see, and frequently their organisations too. Never browser-safe, and rotation should be accompanied by reading the account's audit log.
github_pat_
GitHub fine-grained personal access token. Scoped to specific repositories and permissions, which makes it better than the classic format, but still a repository credential and still critical. Not browser-safe.
re_
Resend API key. It does not read your database — it sends mail as you, from your domain, to anyone. That is a phishing problem and a domain-reputation problem in one string, and reputation damage outlasts the rotation. Not browser-safe.
SG.
SendGrid API key, two dot-separated segments after the prefix. Same category and same consequences as above.
xoxb-, xoxa-, xoxp-, xoxr-, xoxs-
Slack tokens: bot, app, user, refresh and workspace. What they reach depends on the scopes granted at install, and a user token in particular can read whatever that person can read, which in most workspaces is a great deal. Not browser-safe.
sk.eyJ
Mapbox secret token. Note the trap: Mapbox public tokens begin pk. and are entirely browser-safe, while sk. tokens manage your account and are not. The two look almost identical at a glance, and the difference is one character.
The three identified by structure, not by prefix
Some credentials have no fixed leading string and are recognised by their shape instead.
Three base64url segments separated by dots
A JSON Web Token. In a Supabase project this is the legacy key format, and it is the one case where the string tells you its own severity — the payload can be decoded without any secret at all, because base64 is an encoding, not encryption.
echo 'eyJhbGciOiJIUzI1NiJ9.EXAMPLE_PAYLOAD.EXAMPLE_SIG' | cut -d. -f2 | base64 -d
Read the role claim. anon and authenticated belong in a browser. service_role bypasses every policy you have written and is a full database compromise. A token issued by supabase-demo is the local development default that supabase start generates identically on every machine — it is not a leak and should not be reported as one.
A URI with credentials in the authority
Postgres and MongoDB connection strings: a scheme, a username, a password, a host. One field containing everything needed for direct, unmediated database access.
postgres://example_user:EXAMPLE_PASSWORD@db.example.test:5432/appdb
These reach a browser almost exclusively through import boundaries — a shared config module, or a barrel export that pulls a server-only value into client code. Never browser-safe, and the fix is structural rather than a matter of care.
A PEM armour header
A line beginning -----BEGIN and ending PRIVATE KEY-----, with or without an RSA, EC, DSA, OPENSSH or PGP qualifier. Service-account keys arrive this way inside JSON credentials files, which is how they end up bundled — somebody imported the whole file. Never browser-safe under any circumstance.
A note on forty characters of base64
An AWS secret access key has no prefix at all and is simply forty base64 characters, which is far too common a shape in minified JavaScript to report on its own. Chunk hashes, content digests and minifier output all match it. A finding of this kind is only meaningful alongside corroborating context — an access key ID nearby, or an AWS-specific variable name. On its own it is noise, and a scanner that reports it is costing you more attention than it saves.
If you want the same identification performed across every chunk your site serves, rather than one string at a time, that is what the scanner does.