Virus Website Checker Says Clean. Your API Key Says Otherwise.

A virus website checker only looks for malware served to visitors. It won't catch a secret API key sitting in your own JS bundle. Here's the difference.

Barret8 min read

You ran your app through a virus website checker before launch, and it came back clean. No malware, no blocklist hits, no phishing warnings. That felt like a security check. It wasn't, not for the risk that actually matters to an app you built yourself.

A virus website checker (sometimes called a malicious link checker or dangerous site checker) answers one question: will this site attack the person visiting it? That's the right question when deciding whether to click a link a stranger sent you. It's the wrong question when the site is your own app, because a clean scan there says nothing about what your app hands out to every visitor by accident, sitting in plain text in code your browser already downloaded: an API key in your JavaScript bundle, invisible to any malware scanner and readable by anyone who opens dev tools.

⚡ TL;DR

  • A virus website checker looks for malware served to visitors: bad scripts, drive-by downloads, phishing patterns, blocklisted domains. It's built to protect people clicking a link, not to audit a site you own.
  • An exposed API key is a different problem entirely: a credential your own code leaks, sitting readable in your JS bundle, not code that attacks anyone.
  • Some keys in your bundle are supposed to be there (a Supabase anon key, a Stripe pk_live_ key) and are not an emergency. Others (sk_live_, a Supabase service_role key, a raw OpenAI or AWS key) are, and a virus checker will never tell you which is which.
  • Checking your own app for leaked keys takes about as long as running a virus check, aimed at a different question.

What a virus website checker actually looks for

Malware scanners and malicious link checkers work off a handful of signals: does this domain match a known blocklist of phishing or malware sites, does the page try to serve an executable or a drive-by download, does a script on the page match known malicious code, is the SSL certificate valid, is the domain suspiciously new or spoofing a real brand. These are useful, well-established checks. If a friend forwards you a link and you want a fast gut check before clicking, a dangerous site checker is the right tool for that.

What all of that has in common: it checks whether the site does something harmful to the visitor. Malware is code written to attack whoever loads the page, planting a script, redirecting to a scam, trying to install something. That's the threat model a virus checker is built for.

Why "clean" on a virus scan says nothing about your own app

If you built your app with an AI coding tool and ran it through a malicious link checker before launch, a clean result tells you your app isn't attacking its own visitors. It doesn't check whether your app is accidentally handing those same visitors something valuable: a working credential for your database, your payment processor, or your AI provider account.

That's not malware. Nobody put a malicious script on the page. The problem is a leaked secret: a piece of text that should have stayed on your server, shipped instead in the JavaScript bundle every browser downloads when it loads your site. Exposed API keys in frontend code are one of the most common gaps in apps built quickly with an AI tool, because the AI doesn't automatically know which keys are meant for the browser and which aren't. It writes code that works in the demo, nothing more.

The two problems need different tools. A malware scan crawls your page looking for bad behavior. Finding a leaked key means reading the actual JS files your app ships and checking them for key patterns. No blocklist catches that, because the bundle itself isn't malicious. It's carrying a secret it shouldn't.

How an attacker finds a leaked key (it's not sophisticated)

This is the part that should change how you read "clean" scan results. An attacker doesn't need a zero-day or a custom exploit to find a leaked key. They open your site, view page source or the Network tab in dev tools, and search your bundle for text patterns:

sk_live_
service_role
sk-proj-
AKIA

That's grep against a public file. Your JS bundle is not private; anyone who loads your site has a full copy of it in their browser cache. A secret key in there isn't "hidden in the code," it's published and downloadable by anyone who visits, real customer or bot.

Which keys are actually a problem (this is the part most checkers get wrong)

Not every key showing up in your bundle is bad news, and this is where a lot of security tools, and a lot of anxious founders, get it wrong. Some keys are built to be public. Others aren't, and finding one of those means stopping what you're doing.

🐺 Not a real problem

A Supabase anon key or a Stripe publishable key (pk_live_...) in your JavaScript bundle is working as designed. Both platforms are built so the browser needs these to talk to their APIs at all, and their security model assumes anyone can see them. A scanner that flags either one as "critical" is crying wolf. See publishable vs. secret Stripe keys for exactly which prefix is which.

⚠️ Watch out

A Stripe secret key (sk_live_...), a Supabase service_role key, or a raw OpenAI, Anthropic, or AWS key sitting in your frontend bundle is a real emergency. These exist to bypass the restrictions the public keys respect: service_role skips Row Level Security (RLS) entirely, sk_live_ can move money on your Stripe account, and a raw AI provider key can run inference against your account with no limit but your billing settings.

The pattern holds across every platform: if a key's job is authenticating as a caller with elevated power, it belongs on your server, never in code the browser can read. If a key's job is identifying your project publicly, it's meant to be visible, and the real protections live elsewhere (RLS policies, Stripe's dashboard controls). How to secure an API key in your frontend walks through where those protections belong.

An exposed OpenAI or Anthropic key shows why this distinction matters in dollars, not in the abstract. That kind of key doesn't unlock a database of user records. It unlocks your billing account, and anyone who finds it can run requests against it until you notice. What happens after an exposed OpenAI key gets found is a bill in your name for usage you never authorized, not a data breach with a headline.

How to check your own app right now

You don't need to be a developer to do this. It's the same kind of look-and-check as running a virus scan, aimed at a different question.

  1. Open your live, deployed site (not localhost) in a normal browser tab.
  2. Right-click and choose "View Page Source," or open dev tools and go to the Sources or Network tab.
  3. Find your JavaScript files, usually named something like main.[hash].js or under a _next/static folder.
  4. Search that file (Ctrl+F or Cmd+F) for each string, one at a time: sk_live_, service_role, sk-, AKIA, service-account.
  5. A public-by-design match (a clearly labeled anon key, a pk_live_ key) is fine. A dangerous match means rotating that key immediately and moving the logic that uses it to your backend.

A single JS file can run to hundreds of kilobytes of minified code, so doing this by hand across your whole bundle, on every deploy, gets tedious fast. That's the part worth automating.

Want the 60-second version instead?

Paste your link and get a free, read-only report of what an attacker sees on your live site. No login, no install, no code to read.

Scan my site free →

Why this keeps happening in AI-built apps

An AI coding tool writes whatever code makes the feature work in the moment. Ask it to "call the OpenAI API from the chat component" and it will often write that call directly in your frontend code with the key inline, because that's the shortest path to a working demo. It isn't tracking which side of your app is public and which is private unless you tell it to. The fix, usually moving that call to a server route, is small, but it has to happen deliberately: nothing about a virus website checker catches it, because the bundle isn't doing anything malicious. It's leaking.

A one-time check isn't enough, either. Every new feature your AI tool ships is a new chance for a key to land somewhere it shouldn't, and the gap you closed last month can reopen the next time it reaches for the easiest working code path again.

FAQ

I ran a virus website checker on my app and it came back clean. Is that enough before I launch?

It confirms your app isn't serving malware, which is worth knowing, but it doesn't confirm your app is safe to launch. A virus website checker (or malicious link checker) looks for phishing and malware signals aimed at your visitors, not leaked API keys, missing Row Level Security (RLS) policies, or open storage buckets. A clean malware result and a leaked sk_live_ key in your JS bundle can both be true at once, since they're unrelated questions.

My scanner flagged my Supabase anon key or Stripe publishable key as exposed. Should I panic?

No. Both are meant to be visible in your browser code; that's how those platforms are designed to work. A tool that treats either one as a critical finding is crying wolf. The real risk sitting behind a Supabase anon key is missing or misconfigured RLS, not the key itself.

What should I do if I find a real secret key in my bundle?

Rotate it immediately in the provider's dashboard (Stripe, Supabase, OpenAI, and AWS all support this), then move whatever code used that key to a server-side route so the browser never sees it again. Check your provider's usage or billing logs for activity you don't recognize while you're there.

The bottom line

A virus website checker answers "will this site hurt the person visiting it," a real, useful question for links you didn't write. It's a different question from "does my own app leak a secret it shouldn't," and no malware scan answers that one. An attacker can find a leaked key in your bundle in the time it takes to open dev tools and search for a string. The only real defense is checking for it yourself, on every deploy, since your AI tool ships new code, and new chances to leak a key, every time you ask for a feature.

Is your site hackable? Find out in 60 seconds.

Is My Site Hackable? scans your live app for the exact gaps in this article (exposed keys, missing RLS, open buckets) and tells you what's a real risk and what's a false alarm. Paste your link, get a free report. No login, no install.

Run my free scan →