Deploy Safely

Scorecard

FLeaking

We found 13 critical issues a visitor can already see.

Sample vulnerable app · score 0 of 100 · Oct 19, 2026, 11:08 PM UTC

Critical
13
High
5
Medium
1
Low
2
Note
1

What we found

Critical

JavaScript file /assets/app.js

A database password is in the public page

The page includes a database address with a username and password.

A database link with a password was visible. The password was not saved.

That password can open the database directly, past any app-level rules.

Fix prompt

A database connection string with a password is in public client code. Remove it. The browser must never talk to the database with a password. Rotate the database password. Use a server-only environment variable for the connection string.

Critical

JavaScript file /assets/app.js

A GitHub token is in the public page

This token can read or change repositories, depending on what it was allowed to do.

The token starts like ghp_…Ab9Q. The full token was not saved.

A visitor can copy it and use your GitHub access.

Fix prompt

A GitHub personal access token is in public client code. Remove it. Revoke the token on GitHub now. If the app needs GitHub, call the GitHub API from a server using a token stored as an environment variable.

Critical

JavaScript file /assets/app.js

A private key is in the public page

A private key in the browser is like publishing the password to a server or certificate.

A private key header was visible. The key body was not saved.

Anyone can download it and use it.

Fix prompt

A PEM private key is present in a public file. Remove the key from the repository and from client code. Treat it as stolen: generate a new key pair and revoke the old one. Private keys belong only on the server or in a secrets manager.

Critical

JavaScript file /assets/app.js

A SendGrid key is in the public page

This key can send email as your domain.

The key starts like SG.A…m2Np. The full key was not saved.

Spammers look for these keys and burn the domain's reputation.

Fix prompt

A SendGrid API key is in public client code. Remove it, delete the key in SendGrid, and send mail only from the server.

Critical

JavaScript file /assets/app.js

A Slack token is in the public page

This token can post messages or read workspace data, depending on its type.

The token starts like xoxb…2Np4. The full token was not saved.

Anyone who views the page source can take it.

Fix prompt

A Slack token (it starts with xox) is in public client code. Remove it and revoke it in the Slack app settings. Call Slack only from a server that reads the token from an environment variable.

Critical

JavaScript file /assets/app.js

A Stripe secret key is in the public page

Stripe secret keys and restricted keys can move money and read customer data. The publishable key (pk_) is the only Stripe key that belongs in the browser.

The key starts like sk_l…w8Zk. The full key was not saved.

Someone who copies this key can act on your Stripe account.

Fix prompt

A public JavaScript file contains a Stripe secret or restricted key (sk_ or rk_). Remove it from the client. The browser may only use a publishable key (pk_). Move charges, refunds, and customer lookups to a server route that reads the secret from an environment variable. Roll the exposed key in the Stripe dashboard immediately.

Critical

JavaScript file /assets/app.js

A Supabase service role key is in the public page

The service role key skips every Supabase lock, including Row Level Security. It must never be in the browser. We did not use this key.

The token's role is service_role. The token itself was not saved.

Anyone who loads the page can copy this key and read or change every row in the database.

Fix prompt

The frontend bundle contains a Supabase service_role key. This key bypasses Row Level Security. Remove it from every client file, including env variables that start with NEXT_PUBLIC_, VITE_, or PUBLIC_. Keep the service role key only in a server environment variable. In the Supabase dashboard, rotate the service role key now, because this copy is public. The anon key may stay in the browser. Add Row Level Security policies so the anon key cannot read other people's rows.

Critical

JavaScript file /assets/app.js

An Amazon Web Services access key is in the public page

This key ID can be paired with a secret to control cloud resources. It should never ship in JavaScript.

The key id starts like AKIA…EF01. The full id was not saved.

Attackers hunt for these IDs and try the nearby secret. Cloud bills can grow fast.

Fix prompt

A public file contains an AWS access key ID (it starts with AKIA or ASIA). Remove it and any nearby secret access key from client code. Use a server role or a short-lived credential instead. Deactivate the exposed key in the AWS IAM console and check CloudTrail for unexpected use.

Critical

JavaScript file /assets/app.js

An Anthropic secret key is in the public page

This key can use your Claude account. It does not belong in the browser.

The key starts like sk-a…0Hd3. The full key was not saved.

A visitor can copy it and make requests billed to you.

Fix prompt

A public JavaScript file contains an Anthropic secret key (it starts with sk-ant-). Remove it from all client code. Call Claude only from a server route that reads the key from an environment variable. Rotate the key in the Anthropic console now, because this copy is public.

Critical

JavaScript file /assets/app.js

An OpenAI secret key is in the public page

This key can spend money on your OpenAI account and read data the key is allowed to see. It should live only on a server.

The key starts like sk-p…Jc5V. The full key was not saved.

Anyone who loads your site can copy this key from the browser and use it as you.

Fix prompt

A public JavaScript file contains an OpenAI secret key (it starts with sk-). Remove every secret OpenAI key from client-side code. Move the call to a server-only route that reads OPENAI_API_KEY from an environment variable. Then rotate the key in the OpenAI dashboard, because the old one is public. Do not print the key in logs or error messages.

Critical

/.env

Your .env file is public

The site serves /.env to anyone. That file usually holds secret keys and database passwords.

Variable names visible: OPENAI_API_KEY, DATABASE_URL. Values were not saved.

A visitor does not need to hack anything. They can open the file.

Fix prompt

The web server is serving the /.env file to the public. Stop publishing dotfiles and secret files. On Vercel and similar hosts, environment variables belong in the project settings, not in a file that is deployed as a public asset. Remove .env from the published folder, rotate every secret that was in it, and confirm that opening https://YOURDOMAIN/.env returns a not-found page.

Critical

/.git/config

Your Git folder is public

The site serves /.git/config. That means the source history may be downloadable.

The Git config file is readable. Its contents were not saved.

Git history often still contains old passwords even after they were deleted from the latest code.

Fix prompt

The site is serving /.git/config. Stop the host from publishing the .git directory. If this is a static export, do not copy the .git folder into the public directory. Assume the repository history is public and rotate any secret that was ever committed.

Critical

/.git/HEAD

Your Git HEAD file is public

The site serves /.git/HEAD, which is a sign the whole .git folder may be public.

The Git HEAD file is readable. Its contents were not saved.

From that folder, someone can often rebuild your source code.

Fix prompt

https://YOURDOMAIN/.git/HEAD is publicly readable. Block the entire /.git path on the host and rotate secrets that lived in the repository.

High

JavaScript file /assets/app.js

A Resend key is in the public page

This key can send email through your Resend account.

The key starts like re_A…0Hd3. The full key was not saved.

A public email key gets abused quickly.

Fix prompt

A Resend API key (it starts with re_) is in public client code. Remove it, rotate it in Resend, and send email only from server code.

High

vulnerableprojectref1.supabase.co / profiles

The “profiles” table answers visitors who are not signed in

Supabase returned a row from “profiles” when we used only the public anon key. We asked for one row and did not save it. Row Level Security is missing, or a policy lets everyone read this table.

The table name is profiles. No row contents were saved.

If a stranger can read one row, they can usually read the rest: emails, notes, files, or whatever the table holds.

Fix prompt

In Supabase, the public table "profiles" returns rows to the anon key with no signed-in user. Enable Row Level Security on "profiles" and on every other table in the public schema. Add policies that only allow a user to read and write their own rows (auth.uid() = user_id), or a tighter rule that fits this table. Do not use the service_role key in the browser to “make it work.” After the change, confirm that opening the REST URL with the anon key returns an empty list or an error, not real rows. Existing copied data should be treated as public.

High

vulnerable-demo.firebaseio.com

The Firebase database answers visitors

We requested one shallow look at the Realtime Database and it returned data without a login. We did not save the data. The security rules are probably open.

The database responded to a signed-out request. No records were saved.

Open Firebase rules are a common way a whole customer list ends up public.

Fix prompt

The Firebase Realtime Database at this project returns data to signed-out visitors. In the Firebase console, set the Realtime Database rules so reads and writes require auth, for example: { "rules": { ".read": "auth != null", ".write": "auth != null" } }. Tighten that further so users can only touch their own path. Do not leave ".read": true. Deploy the rules and confirm that opening the database URL with .json is denied.

High

vulnerable-demo / customers

The Firestore collection “customers” is readable without a login

Firestore listed a document to a request that only used the public web API key. We did not save the document. The security rules are probably open.

The collection name is customers. Document contents were not saved.

If one collection is open, others often are too.

Fix prompt

Firestore in project "vulnerable-demo" returned a document from "customers" without a signed-in user. Update firestore.rules so that collection is not world-readable. A safe starting point is to require request.auth != null and to match the user id on the document. Deploy the rules from the Firebase console. Do not work around this by hiding the API key; that key is supposed to be public, and the rules are the lock.

High

/.npmrc

Your .npmrc file is public

The site serves /.npmrc. That file sometimes contains a package-registry token.

An npm auth token setting is visible. The token value was not saved.

A registry token can publish packages or download private ones.

Fix prompt

https://YOURDOMAIN/.npmrc is publicly readable. Remove it from the deploy. If it contains an _authToken, revoke that token in npm (or the registry you use).

Medium

/assets/app.js.map

Your original source code is public

A source map is available next to the JavaScript. It can include the original file names and, often, the original code.

Original file names include: src/lib/supabase.ts, src/pages/Admin.tsx. The source was not saved.

Source maps make it much easier to find leftover keys, hidden routes, and comments you did not mean to publish.

Fix prompt

The production JavaScript references a public source map, and that map includes original source. Turn off production source maps in the build (for Vite, build.sourcemap false; for Next.js, productionBrowserSourceMaps false). Delete the existing .map files from the host. Do not rely on source maps to hide secrets; remove the secrets too.

Low

the main page response

A few browser safety headers are missing

The public page does not send: Content-Security-Policy, X-Content-Type-Options, X-Frame-Options or frame-ancestors, Referrer-Policy. These headers tell browsers how to treat your site. They are not the same as a leaked key, but they are easy to add.

Missing: Content-Security-Policy, X-Content-Type-Options, X-Frame-Options or frame-ancestors, Referrer-Policy.

Without them, browsers are more willing to load your site inside a trick frame or to sniff a file as a script.

Fix prompt

Add these HTTP response headers on the public site: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options: nosniff, X-Frame-Options: DENY (or Content-Security-Policy frame-ancestors 'none'), and Referrer-Policy: strict-origin-when-cross-origin. On Vercel this can go in vercel.json headers or in next.config. Do not weaken the app to make the headers pass; start with a simple policy and tighten it.

Low

JavaScript file /assets/app.js

A Google API key is in the page

Firebase and Maps apps often include a Google key in the browser. Lock it to your domain in Google Cloud so other sites cannot spend it.

The key starts like AIza…gAb9.

An unlocked key can be copied and used from somewhere else, which can create a surprise bill.

Fix prompt

A Google API key is in the public page. In Google Cloud, restrict that key to your website's domain and to only the APIs you use. If this key is a server key, move it out of client code and rotate it.

Note

JavaScript file /assets/app.js

Your Supabase public key is in the page. That part is normal.

Supabase apps include a public key, called the anon key, in the browser. By itself that is not a leak. The danger is a service role key, or tables that return rows to people who are not signed in.

The token's role is anon. That is the public Supabase key.

You do not need to hide the anon key. You do need locks on the tables it can reach.

Fix prompt

The Supabase anon key in the browser is expected. Do not replace it with the service_role key. Turn on Row Level Security for every public table and add policies so visitors can only read the rows they should see.

What this check included

  • Public page
  • Browser safety headers
  • 1 JavaScript file
  • Common private files (.env, .git, .npmrc)
  • Supabase tables using the public anon key
  • Firebase open-rule signals
  • This check looks only at what a visitor’s browser can already see. It does not try passwords, guess hidden pages, or use any secret it finds.

Email me the fix walkthrough

We'll send a private link to the full report. The public scorecard stays free of secret details.

F for sample.deploysafely.test · Deploy Safely