What it does.
What it won’t.

Does It Leak? is a defensive posture checker, not an attack tool. It looks at your app the way a browser already does, and grades what it finds. Here is exactly how it behaves — if anything below isn’t literally true of what we run, treat it as a bug.

What it does

The scanner is passive and read-only. Every request is a plain GET, the same kind your browser makes when it loads a page. From the URL you submit, it fetches and analyses only:

  • the page’s HTML;
  • the same-origin JavaScript and CSS it links to;
  • any source maps those bundles reference;
  • the HTTP response headers that come back with them.

Against those assets it checks for the classic vibe-code sins: secret keys shipped to the browser (Supabase service_role, Stripe sk_live, OpenAI, AWS, Google), Firebase configs with wide-open rules, public source maps, inlined .env blocks, and missing security headers (CSP, HSTS, clickjacking protection, HTTPS). Secret detection validates a token’s shape only.

Requests identify themselves with a descriptive User-Agent — DoesItLeak-Scanner/1.0 (+https://doesitleak.app/about) — and honour your robots.txt. If a path is disallowed for our agent, the scan skips it and says so (“couldn’t fetch (robots-disallowed)”) rather than fetching it anyway. Each scan is capped at 40 asset fetches, 8 MB, 20 seconds, and 4 concurrent requests to your origin; past those limits it grades on partial data and tells you it was truncated.

What it never does

  • No exploitation. It never sends payloads, never tries to bypass authentication, never brute-forces or enumerates users or records.
  • No chasing keys. If it spots a key-shaped string, it never calls the service that key belongs to — not even to “verify” it. Detection stops at “this pattern is present in a public asset.”
  • No writing. Every request is a read-only GET. Nothing is submitted, changed, or deleted on your app.
  • No probing by default. The optional well-known-file check (does GET /.env return 200?) is off by default. When enabled it reads the status code only — never the file’s contents.

Consent & privacy

You can only scan an app you own or are authorised to test. Every scan requires you to tick that attestation first — the request is rejected without it.

Results are private by default. A grade is visible only to the browser that ran it until you explicitly choose to publish it. Publishing is what puts a report on a shareable link, in the badge, and on the leaderboard — nothing appears there until you decide it should.

How your data is handled

  • We never store a full secret. When a key-shaped string matches, we keep only a redacted fingerprint (for example sk_••••EFGH) — never the full value, not in the database, not in logs. A safeguard at the write path scrubs anything that still looks like a full secret before it can be saved.
  • We never store your IP. For abuse control we keep only a salted hash of it (sha256(ip + salt)), which we can’t reverse into an address.

The grade

Every scan starts at 100 and loses points by severity — 40 for a critical, 20 for a high, 8 for a medium, 3 for a low — then maps to a letter. Two rules are deliberate and non-negotiable: a single critical (like a leaked service-role key) caps you at D− no matter how clean everything else is, and two or more criticals is an automatic F. A leaked master key should fail you.

What it can’t tell you

Because it only sees what a browser downloads, a clean grade means “nothing leaked in your public assets” — not “your app is secure.” It can’t see your server code, your database rules, or logic bugs behind an API. Treat an A as clearing the floor, not the ceiling.

Scan your app →