MLVibeScan

Sample report

What a complete report looks like

This is a made-up report for a domain that does not exist — but the findings are the ones we see most often in real scans. Fully expanded, with the location, the evidence and a ready-made fix. This is exactly what you get for your own domain after unlocking.

Made-up data. The domain beispiel-app.de does not exist — a sample report about someone else’s real site would be publishing their weaknesses.

Security report for

beispiel-app.de

Scanned on 1 August 2026 · Automatically deleted on 30 October 2026

E

Security grade

Fix this soon

  • 2

    critical

  • 1

    high

  • 2

    medium

  • 1

    low

  • 1

    info

  • 1× Credentials
  • 1× Database
  • 1× Shipped files
  • 2× Delivery
  • 1× Email delivery
  • 1× Detected setup

7 findings across 6 areas

criticalCredentials

OpenAI key in the shipped JavaScript

An OpenAI key sits in plain text in your frontend bundle. Any visitor can read it, and automated bots comb public bundles looking for exactly this. The key counts as compromised the moment it was shipped — even if you replace the bundle now.

Where we found it:
/assets/index-Bq7fK2mP.js, Zeile 1842
Auszug:
const openai=new OpenAI({apiKey:"sk-proj-4f8a2…",dangerouslyAllowBrowser:true})

How to fix it

Revoke the key immediately at platform.openai.com/api-keys — not later; the old one is irreversibly public.

Then: the call belongs on the server, not in the browser. Add your own route (an edge function or /api/chat) that holds the key server-side and forwards the request. The frontend then only calls your route.

`dangerouslyAllowBrowser: true` is the SDK telling you this path was never intended.
criticalDatabase

Supabase table “profiles” readable without Row Level Security

We queried the table using the public anon key from your frontend and got rows back. That means anyone who opens your site can download the entire table — including other users’ rows.

Where we found it:
https://xyzcompany.supabase.co/rest/v1/profiles?select=*
Auszug:
HTTP 200 · 1.284 Datensätze · Felder: id, email, full_name, stripe_customer_id

How to fix it

In the Supabase console under Authentication → Policies for the `profiles` table:

```sql
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Read own profile"
  ON profiles FOR SELECT
  USING (auth.uid() = id);

CREATE POLICY "Update own profile"
  ON profiles FOR UPDATE
  USING (auth.uid() = id);
```

Note: `ENABLE ROW LEVEL SECURITY` on its own blocks everything — without a policy your own app loses access too. The two belong together.

Then scan again — this check is the proof that it worked.
highShipped files

Source maps publicly reachable

Your source maps sit next to the bundle and can be fetched without signing in. That reconstructs your unbuilt original code — filenames, comments and your project’s folder structure included.

Where we found it:
/assets/index-Bq7fK2mP.js.map
Auszug:
HTTP 200 · 2,1 MB · "sources":["src/lib/auth.ts","src/lib/stripe.ts", …]

How to fix it

In `vite.config.ts`:

```ts
export default defineConfig({
  build: { sourcemap: false },
});
```

For Next.js: `productionBrowserSourceMaps: false` (that is already the default — check whether something set it to `true`).

Then rebuild and redeploy. Delete existing `.map` files on the server: a new build does not necessarily remove them.
mediumDelivery

No Content-Security-Policy set

Without a Content-Security-Policy, injected code in your page can load arbitrary scripts. That is the difference between a harmless and an exploited XSS hole.

Where we found it:
https://beispiel-app.de/
Auszug:
Antwortheader enthalten weder content-security-policy noch content-security-policy-report-only

How to fix it

A starting point for a typical SPA:

```
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
```

Roll it out as `Content-Security-Policy-Report-Only` first and watch the browser console for what would be blocked. Only switch to the enforcing header once nothing important shows up.
lowDelivery

Referrer-Policy missing

Without a Referrer-Policy the browser sends your page’s full address to third-party servers whenever someone clicks an outbound link — query parameters included.

Where we found it:
https://beispiel-app.de/
Auszug:
Antwortheader enthalten kein referrer-policy

How to fix it

Add the header:

```
Referrer-Policy: strict-origin-when-cross-origin
```

This is what modern browsers already default to — setting it explicitly makes the behaviour independent of the visitor’s browser.
mediumEmail delivery

No DMARC record

Without DMARC anyone can send email using your sender address. For phishing aimed at your own users that is half the work done — and it hits exactly the people who trust you.

Where we found it:
_dmarc.beispiel-app.de
Auszug:
NXDOMAIN — kein TXT-Eintrag vorhanden

How to fix it

Add a TXT record with the name `_dmarc`:

```
v=DMARC1; p=none; rua=mailto:dmarc@beispiel-app.de
```

Start with `p=none` — it rejects nothing yet but collects reports on who sends in your name. Once the reports look clean, move to `p=quarantine` and later `p=reject`.

Starting at `p=reject` can make your own mail from newsletters or billing systems undeliverable.
infoDetected setup

Built with Lovable, Supabase as the backend

Detected from the bundle structure and the addresses being called. This is not a defect — it decides which deep checks make sense for your app at all.

Where we found it:
https://beispiel-app.de/
Auszug:
lovable-tagger im Bundle · xyzcompany.supabase.co als API-Ziel

How to fix it

Nothing to do. We list it because it determines which checks we run for you — and because you should know what is visible about your setup from the outside.

So how does yours look?

The scan is free and takes about twenty seconds. You see straight away how many findings there are and how serious they are.

Scan your own app for free