Sample report: our own test app
It's a real, unedited scan by the live Unspill scanner of unspill-fixture.vercel.app, a test app we built and own. We planted fake secrets, an exposed .env file, a .git folder and source maps in it on purpose, so it scores badly. None of the keys are real. Evidence is masked exactly as it is in every real report. Scanned 2026-10-26 13:27 EDT.
In a real app you'd fix the 7 critical/high issues first. For leaked keys: revoke them at the provider before anything else.
Anyone can download every secret in this file. Treat all of them as compromised.
- Delete .env from the deployed/public directory and redeploy.
- Rotate every secret that was in the file.
- Add .env* to .gitignore and keep env values in your host's environment-variable settings.
Everything shipped to the browser is public. Rotate (revoke and re-issue) these keys first, then move them server-side.
- Roll the key now in the Stripe Dashboard (Developers → API keys → ⋯ → Roll key).
- Remove it from client code and VITE_/NEXT_PUBLIC_ variables; keep only pk_ keys in the browser.
- Create Checkout Sessions/PaymentIntents in a server function and verify webhooks server-side with whsec_.
- Review Stripe Dashboard → Developers → Logs for API calls you did not make.
Everything shipped to the browser is public. Rotate (revoke and re-issue) these keys first, then move them server-side.
- Revoke the key in your provider's dashboard and create a new one.
- Set a monthly spend limit at the provider.
- Call the AI API from a server function that keeps the key in a server-only env variable.
- Add authentication and per-user rate limits to that function so it can't become a free proxy.
Everything shipped to the browser is public. Rotate (revoke and re-issue) these keys first, then move them server-side.
- Deactivate and delete the key in IAM → Users → Security credentials.
- Check CloudTrail and Billing for activity you didn't start.
- Use S3 presigned URLs generated by a server function for uploads.
- Give server credentials least-privilege IAM policies.
Everything shipped to the browser is public. Rotate (revoke and re-issue) these keys first, then move them server-side.
- Delete the key: Google Cloud Console → IAM & Admin → Service Accounts → Keys.
- Remove the JSON file and firebase-admin from client code.
- Use the regular Firebase web SDK in the browser, protected by Security Rules.
- Run admin tasks only in Cloud Functions or another server.
Everything shipped to the browser is public. Rotate (revoke and re-issue) these keys first, then move them server-side.
- Rotate now: in the Supabase dashboard go to Project Settings → API keys and roll/revoke the exposed secret or service_role key.
- Remove it from all client code and any VITE_/NEXT_PUBLIC_ env variable.
- Move privileged queries into an Edge Function or server route that reads the key from a server-only secret.
- Review your database for unexpected changes, and check Auth users and Storage for anything you did not create.
Attackers can often download your whole repository history, including secrets that were ever committed.
- Remove .git from the deployed directory, or block /.git in your server config.
- Rotate any secret that has ever been committed to the repo.
- Deploy from a build output folder or via Git integration instead of uploading the project folder.
- Add a Content-Security-Policy header via vercel.json, _headers or next.config.js.
- Start with Content-Security-Policy-Report-Only to see what would break, then enforce.
- Allow your API/Supabase domains in connect-src.
- Add X-Frame-Options: DENY (or SAMEORIGIN if you embed yourself).
- Or add frame-ancestors 'none' to your Content-Security-Policy.
Browsers block or warn on these; anything loaded over HTTP can be tampered with.
- Change the listed http:// URLs to https://.
- If a resource has no HTTPS version, host it yourself.
- Optionally add upgrade-insecure-requests to your CSP.
Anyone can rebuild your original front-end source code (comments, file names, internal routes) from these.
- Vite: set build.sourcemap to false (or 'hidden' and upload maps to your error tracker).
- Next.js: make sure productionBrowserSourceMaps is not set to true.
- Redeploy, and check that yourfile.js.map now returns 404.
Everything shipped to the browser is public. Rotate (revoke and re-issue) these keys first, then move them server-side.
- Look up each masked value in your code (search by the first characters shown).
- If it's a real secret: rotate it and move it server-side.
- If it's a public ID (e.g. analytics), you can ignore this finding.
Your Supabase URL and public (anon/publishable) key are in the page, which is normal. It also means anyone can query every table that lacks correct RLS policies. We did not query your database; run the 2-minute self-check in the guide.
- Open Supabase → SQL Editor and run the RLS status query from the guide.
- Enable RLS on every table in the public schema.
- Replace any policy that uses USING (true) on private data with one scoped to auth.uid().
- Open Supabase → Advisors → Security Advisor and fix every error it lists.
Firebase web config is public by design; your Firestore, Realtime Database and Storage rules are the only thing protecting data. We did not query them.
- Firebase Console → Firestore → Rules: make sure there's no 'allow read, write: if true'.
- Do the same for Realtime Database and Storage.
- Scope access with request.auth.uid.
- Use the Rules Playground to test as an unauthenticated user.
- Add X-Content-Type-Options: nosniff to every response.
- Add Referrer-Policy: strict-origin-when-cross-origin (or no-referrer).
- Change the listed http:// URLs to https://.
- If a resource has no HTTPS version, host it yourself.
- Optionally add upgrade-insecure-requests to your CSP.
Fine for truly public data; risky if this route returns anything user-specific.
- Allow only your own front-end origins (an explicit list), never reflect the request's Origin.
- Never combine credentials: true with a wildcard or reflected origin.
- Public, non-user data can keep *; anything user-specific can't.
- Add Permissions-Policy: camera=(), microphone=(), geolocation=() (leave out any feature you use).
Firebase web keys are meant to be public. Other Google keys (Maps, Gemini/AI Studio) must be restricted by HTTP referrer and API, or kept server-side.
- Google Cloud Console → APIs & Services → Credentials: add HTTP referrer restrictions and limit the key to the APIs it needs.
- Never call Gemini directly from the browser with an AI Studio key; proxy it server-side.
What we checked
Passive check of public files only. It cannot see your database rules, server code, or whether one logged-in user can read another user's data.
Scan your own app free Passive, no signup. Only scan apps you own.
Also compare: Unspill vs Lovable Security Scan vs Supabase Security Advisor.