what we check
Every check, in plain words.
47 checks across your live app and your code. Each one says what it means for you first. The ids on the right are what you will see on a finding, if you want to look one up. Every finding in the app also comes with a fix prompt for your builder.
live app scan
Live app scan
What a stranger with a browser can see on your live app: the pages and JavaScript it sends, how it is served, and its HTTPS setup. Runs against the exact address you verified.
Keys in your JavaScript
Everything in your app's JavaScript is downloaded by every visitor. If a secret key ends up in there, it is not secret any more. We look for real, usable keys from dozens of providers and show them redacted (like sk-proj-Ab…9xQ). Keys that are meant to be public, like the Supabase anon key or the Firebase web config, are not treated as leaks.
An AI provider key anyone can copy
Anyone can lift the key from your page and run up your AI bill. The fix is to call the AI from a server function instead of the browser, then rotate the key.
secrets.anthropic-key
secrets.google-ai-key
secrets.groq-key
secrets.openrouter-key
Your Supabase master key is in the browser
This key skips every access rule in your database. In the browser it means anyone can read, change or delete all of your data.
secrets.supabase-secret-key
Your Stripe secret is public
With it, someone can read your customers, issue refunds or create charges on your account.
secrets.stripe-webhook-secret
Other server keys
AWS, GitHub, Resend, SendGrid, Twilio, Slack, database connection strings and more. Each one is a door into a service you pay for.
A secret-sounding setting built into the page
Build tools copy every VITE_, NEXT_PUBLIC_, REACT_APP_ and EXPO_PUBLIC_ variable into the JavaScript. A setting called something like VITE_STRIPE_SECRET is public, whatever is in it.
AI called from the browser
We work out which builder and stack made your app (that is how fix prompts get worded for it), and look at how it talks to AI providers.
The OpenAI or Anthropic SDK runs in the browser
The code turns on a setting literally named dangerouslyAllowBrowser. It means your AI key travels to every visitor, where anyone can copy it.
The browser talks to an AI provider directly
Only safe if each visitor brings their own key. If the app uses yours, it is in the page or fetched at runtime, and either way it can be copied.
Browser safety settings
Response headers tell browsers how careful to be with your site. Missing ones are rarely an emergency, and most builders can add them in one prompt.
Your server tells browsers any website may read it
Fine for truly public data. A problem if your API returns anything private, and worse if it also tries to allow your users' cookies.
headers.cors-wildcard
Plain http:// is not sent to https://
Visitors who type your address without https stay on an unencrypted connection.
Browsers are not told to always use HTTPS
HSTS makes browsers refuse the unencrypted version of your site, even on sketchy Wi-Fi.
headers.weak-hsts
No Content Security Policy
A CSP limits which scripts may run on your pages, which blunts the damage if someone manages to inject one.
Your app can be framed by other sites
Another site could load yours invisibly and trick people into clicking buttons in it.
Browsers may guess file types
Without nosniff, a browser can treat an uploaded file as a script.
Full page addresses leak to other sites
Links out of your app can send the full URL, including any tokens in it, to the site you link to.
Your server announces its exact version
It makes looking up known bugs for that version a little too easy.
No way for researchers to reach you
A security.txt file tells people who find a problem where to report it. Custom domains only.
headers.security-txt-expired
Your HTTPS certificate
Platform addresses like lovable.app or replit.app handle this for you. On a custom domain it is worth a look.
Certificate expired or about to
When it lapses, browsers show a full-page warning and most visitors leave.
tls.cert-expiring
tls.cert-expiring-soon
tls.renewal-stalled
Certificate not trusted for this address
Browsers will warn visitors that the connection may not be private.
tls.hostname-mismatch
Old encryption still accepted
TLS 1.0 and 1.1 are retired. Only very old devices need them.
tls.tls11-enabled
tls.weak-negotiated-protocol
Weak certificate key or signature
The certificate uses cryptography that is no longer considered strong.
tls.weak-signature
Pages and forms
We crawl a handful of pages on your app (same address only) and look at forms and the scripts they load.
A form sends data unencrypted
Passwords or personal details typed into the form travel over plain http.
web.pii-form-http
web.form-posts-http
Secure pages load insecure files
An https page pulls in scripts or images over http, which someone on the network could swap out.
Outside scripts loaded without a fingerprint
If that CDN is ever compromised, the altered script runs in your app.
Tracking cookies before consent
Analytics or ad cookies are set before the visitor agrees, which matters if you have visitors in the EU or UK.
Files that should never be public
Asking your live app for a short list of files that should not be served: .env, the .git folder, source maps, platform config.
Downloadable .env, .git and source maps
A single request to your live app is enough for anyone to download these. We check a fixed list of paths and confirm the content is real, not your app's catch-all page.
exposure.git-directory
exposure.source-maps
CORS on your live API
Testing, with plain GET requests, whether your live API lets any other website use your visitors' logged-in sessions.
CORS that lets any site use your users' sessions
If your API echoes back whatever website asks and allows cookies, a malicious page can read private data as whoever is logged in.
api.cors-allows-null-origin
repo scan
Repo scan
What is inside your code on GitHub, read through our GitHub App and never run. On demand, and on paid plans on every push.
Secrets committed to your code
Builders that sync to GitHub (Lovable, Replit, Bolt) and editors like Cursor commit whatever is in the project. If a key was pasted into a file, it is in the repo, and everyone with access to the repo has it.
A live secret key in a source file
We show the file and line, with the key redacted, so you know exactly which key to rotate. Keys in browser code are ranked higher than keys in server code.
A .env file is committed
The file that is supposed to stay on your machine (or in your platform's Secrets pane) is in the repository.
Packages with known holes
Your app is built on hundreds of open source packages. We read your lockfile (npm, pnpm, Yarn, Bun, Poetry and more) and look each version up in OSV.dev, the open vulnerability database.
A package you use has a published vulnerability
We name the package, the version you have and the version that fixes it. One upgrade that clears several advisories counts as one problem.
No lockfile
Without one, each install can pull different versions, and we cannot tell which ones you actually run.
Database rules in your repo
Supabase migrations and Firebase rules files decide who can read your data. We read them in the repo, so a table with no access rules is caught in the code, before it is deployed.
Tables without Row Level Security
A migration creates a table and never turns RLS on, so your app's public Supabase key can read and change it as soon as the migration runs.
Policies that let everyone in
RLS is on, but a policy like using (true) means anyone can read, add, change or delete rows anyway.
repo-rules.policy-anyone-can-insert
repo-rules.policy-anyone-can-read
Database views that skip RLS
A view runs with its creator's rights, so it can show rows the table itself would hide.
Extra permissions handed out
A GRANT that opens a table to anonymous visitors, or a privileged function that can be tricked into running someone else's code.
repo-rules.security-definer-search-path
Firebase rules open to everyone
Your firestore.rules, storage.rules or database.rules.json let anyone read or write without signing in.
repo-rules.firebase-open-storage
repo-rules.firebase-open-rtdb
Firebase rules still in test mode, or too generous
Test-mode rules, parts of the database anyone can change, or rules where any signed-in user can change everything.
repo-rules.firebase-open-write-<service>
repo-rules.firebase-any-user-<service>
Risky code patterns
Patterns that AI-written code gets wrong often, in JavaScript, TypeScript and Python. Some are hints for a human (or your AI) to look at, and say so.
Supabase master key used in browser code
Front-end code creates a Supabase client with the service_role key, which ignores every access rule.
Secrets or AI keys wired into the browser
A secret read from a VITE_ or NEXT_PUBLIC_ variable, or an AI SDK told to run in the browser.
repo-code.ai-key-in-browser
Admin checks that trust the browser
If "is this user an admin?" comes from localStorage, anyone can flip it in their browser's dev tools.
Any website can make logged-in requests to your API
Server code like cors({ origin: true, credentials: true }) lets a page on any site call your API with your users' cookies.
Database queries built from pasted-in text
Values are glued straight into SQL, which lets someone rewrite the query.
repo-code.sql-string-building
Login tokens accepted without checking them
The server reads a token without verifying its signature, so anyone can forge one.
Stripe webhooks that anyone could fake
Your webhook handler does not check the request really came from Stripe, so someone could mark orders as paid.
Passwords hashed with MD5 or SHA-1
If the database ever leaks, these are quick to crack.
A server route that does not check who is calling
An endpoint that changes data without looking for a signed-in user.
Text turned into HTML or code without cleaning
Things like dangerouslySetInnerHTML or eval, fed with data that might come from a user.
repo-code.eval
Shortcuts that weaken security
HTTPS certificate checks switched off, or Math.random used to make tokens.
repo-code.insecure-random
not yet available
Coming to the live app scan
These are being built and are not part of any scan today. We list them so you know what is covered and what is not. Where the repo scan already catches the same problem in your code, we say so.
Live Supabase checks
Checking, with your app's own public key and read-only requests, whether its Supabase tables, storage buckets and auth settings are open to anyone.
Tables and buckets readable with the public key
Until this ships, the repo scan catches the usual cause: migrations that create tables without RLS.
Live Firebase checks
Checking, read-only, whether your Realtime Database, Firestore and Storage answer to strangers.
Open database and storage rules
Until this ships, the repo scan reads your Firebase rules files.
severity
How we rank things
Fix today
Someone could read or change your data, or spend your money, right now, with nothing more than a browser.
Fix this week
A real weakness, but it needs something else to go wrong first, or the damage is limited.
Good to know
Worth tidying up when you are in there. These barely move your grade.
Your grade (A to F) weighs findings by severity, so one open table outweighs a handful of missing headers, and any critical finding means an F however tidy the rest is. The same problem found in several places counts once. A clean scan means none of these checks found a problem, not that the app is perfectly secure: we see what is visible from outside and in your repo, not everything.
Run all of them on your app.
One app is free. No card.