Sicherheitsgrundlagen
Ist ein offener API-Endpunkt ein Sicherheitsproblem? Sieh ins JSON
Dein Scan hat einen offenen API-Endpunkt gemeldet. Ob das zählt, hängt davon ab, was zurückkam, und die meisten hier gehörten der Plattform.

Kurz gesagt
- Ein offener API-Endpunkt heißt: ein Pfad aus dem Code deiner App hat eine Anfrage ohne Login beantwortet, und zurück kam JSON.
- Von denen, die wir über 30.926 Apps fanden, hatte sieben von zehn die Plattform hinterlegt, auf der die App veröffentlicht wurde, und sie geben Einstellungen zurück.
- Entscheidend ist die Frage, ob irgendetwas in der Antwort eine Person beschreibt. Eine Preisliste ist absichtlich öffentlich. Eine Kundenliste war es nie.
Dein Scan kam mit einer Zeile zurück, die nicht wie ein Urteil klingt: einige API-Endpunkte antworten ohne Login. Vielleicht hat es dir auch jemand direkter gesagt und von einem offenen API-Endpunkt gesprochen. Darunter steht eine Adresse, und es ist gut möglich, dass du sie nicht wiedererkennst.
Hier ist der Teil, den Ratgeber um Ratgeber falsch darstellt: der übliche Rat zu diesem Befund lautet, einen Login vor deinen Endpunkt zu setzen, und bei den meisten Apps, die wir gescannt haben, gibt es gar keinen Endpunkt von dir, vor den man einen setzen könnte. Sieben von zehn der gefundenen gehören der Plattform, auf der die App veröffentlicht wurde. Diesen Befund zu lesen beginnt also damit, herauszufinden, wessen Adresse das ist, und die Antwort steht meistens schon in der ersten Zeile dessen, was zurückkommt.
Was ein offener API-Endpunkt in deinem Bericht bedeutet
Es bedeutet, dass ein Pfad aus dem Code deiner App eine Anfrage beantwortet hat, die keinen Login mitführte, und dass JSON zurückkam.
Drei Schritte, und keiner davon ist raffiniert. Wir laden deine App in einem Browser, so wie ein Besucher es tut, und lesen den Code, den dieser Browser heruntergeladen hat. Darin stehen die Adressen, die deine App aufruft, wenn sie Daten braucht. Dann fragen wir jede einzelne nach Daten, ohne Konto, ohne Cookie und ohne Schlüssel. Antwortet eine Adresse mit JSON, das keine Fehlermeldung ist, landet sie im Bericht.
Das hält fest, was passiert ist. Es ist kein Urteil über die Daten, denn nichts, was außerhalb deiner App steht, kann erkennen, ob eine Liste von Dingen eine Liste öffentlicher Dinge ist. Deshalb ist der Befund so formuliert, wie er formuliert ist: diese Endpunkte gaben Daten ohne jede Authentifizierung zurück, das kann bei öffentlichen Daten so gewollt sein, prüfe, dass keiner davon private Informationen preisgibt.
Der Bericht reicht dir also eine Liste von Adressen zum Öffnen. Jede einzelne davon gehört in einem abgemeldeten Browser geöffnet, und die ersten Zeilen der Antwort entscheiden die Sache.
Ist jeder offene API-Endpunkt ein Sicherheitsproblem?
Nein. Es gibt drei Sorten, und nur die dritte ist ein Problem.
Denk an ein Mehrfamilienhaus. Manches darin ist für jeden gedacht, der hereinkommt: die Öffnungszeiten an der Tür, die Fluchtwege, der Aushang über die Aufzugwartung am Dienstag. Irgendwo im selben Haus steht ein Aktenschrank mit den Daten der Mieter. Vom Flur aus sind ein Schwarzes Brett und ein unverschlossener Aktenschrank beide nur Mobiliar, das man öffnen kann, und auseinanderhalten kann man sie nur, indem man liest, was auf dem Papier steht.
| Was geantwortet hat | Wessen Adresse ist das | Wo du stehst |
|---|---|---|
| Plattform-Einstellungen: Cookie-Hinweise, Feature-Schalter | Die deines Builders, in jeder App, die er veröffentlicht | Nichts zu tun |
| Deine eigenen öffentlichen Daten: eine Preisliste, ein Artikel | Deine, und zum Lesen gedacht | Nichts zu tun |
| Zeilen über Personen: Namen, E-Mails, Bestellungen, Nachrichten | Deine, und erreichbar für jeden mit der Adresse | Heute schließen |
Die erste Zeile ist ein Schwarzes Brett, das jemand anderes an die Wand geschraubt hat. Die zweite ist ein Schwarzes Brett, das du absichtlich aufgehängt hast. Die dritte ist der Aktenschrank, und er steht offen, solange es die Adresse gibt.
So prüfst du, was deine Endpunkte zurückgeben
Öffne jede abgemeldet und lies, was ankommt. Das Lesen dauert länger, als der Befund vermuten lässt, und es ist der einzige Schritt, der die Frage beantwortet.
Finde die Adressen. Öffne deine Live-App, drücke F12 für die Entwicklerwerkzeuge des Browsers, klicke auf Netzwerk und lade die Seite neu. Klicke die Anfragen durch, die als JSON zurückkommen. Das sind die Adressen, von denen deine App Daten holt, und die Liste im Bericht ist eine Teilmenge davon.
Frage jede als Fremder. Kopiere eine URL, öffne ein privates Browserfenster, damit du abgemeldet bist, und füge sie ein. Was du siehst, ist genau das, was jeder im Internet an dieser Adresse sieht.
Lies die ersten Zeilen. Drei Dinge können zurückkommen:
- Ein Fehler, eine Abweisung oder
[]. Die Adresse will einen Login, oder für einen abgemeldeten Aufrufer ist nichts darin. Weiter. - Einstellungen. Flags, Schalter, eine Farbe, eine Liste aktivierter Funktionen, eine Versionsnummer. Niemand wird genannt, nichts wird beschrieben. Weiter.
- Zeilen. Eine E-Mail-Adresse, der Name einer Person, eine Bestellsumme, der Text einer Nachricht, eine Telefonnummer. Hier anhalten, das ist die eine.
Wenn du Zeilen findest, ändere eine Zahl in der URL, bevor du den Tab schließt.
Eine Adresse, die bei id=1 den Datensatz einer Person herausgibt und bei
id=2 den einer anderen, gibt alle heraus, und das ist gut zu wissen, bevor du
entscheidest, wie dringend das ist.
Unser kostenloser Scan erledigt die ersten beiden Schritte für dich: er liest im Code deiner App die Adressen, die sie aufruft, fragt jede ohne Login und listet die auf, die mit Daten geantwortet haben. Er dauert etwa 20 Sekunden und braucht kein Konto: scanne deine App. Der dritte Schritt gehört dir, denn nur du weißt, ob ein Name in dieser Liste ein echter Kunde ist.
Die meisten, die wir fanden, gehören der Plattform
In unserem Sweep vom August 2026 hatten 3.852 der 30.926 Apps, bei denen diese Prüfung eine Antwort bekam, mindestens eine Adresse, die ohne Login antwortet. Davon waren 2.705 Base44-Apps, und bei Base44 ist es fast immer dieselbe Adresse.
Es ist /api/consent/config, die Cookie-Einstellungen der Plattform. Wir haben
im September eine Stichprobe gemeldeter Base44-Apps erneut geöffnet, und die
einzige Adresse, die antwortete, war diese. Sie gibt Einstellungen zurück, sie
ist auf allen Apps identisch, und niemandes Daten stecken darin. Der Scanner
meldet sie korrekt, und der Betreiber hat nichts zu beheben.
| Plattform | Apps mit dem Befund | Apps, bei denen die Prüfung antwortete |
|---|---|---|
| Base44 | 2.705 | 5.419 |
| Eigene Domains | 82 | 955 |
| Bolt | 4 | 1.120 |
| Lovable | 8 | 18.518 |
| v0 | 0 | 1.786 |
Eine Plattform fehlt in dieser Tabelle mit Absicht. Auf Replit entfällt ein großer Block der übrigen Befunde, und niemand hat davon eine Stichprobe erneut geöffnet, so wie wir es bei Base44 getan haben, also wissen wir noch nicht, wessen Adressen das sind. Eine Zahl als Problem des Betreibers zu veröffentlichen, bevor jemand hingesehen hat, ist genau der Weg, auf dem eine Plattform-Einstellung von Base44 zur Statistik über nachlässige Betreiber wird. Jede Zahl hier oben stammt aus unserem Scan von 30.998 live geschalteten Vibe-Coding-Apps, der zu jeder die Basis mitveröffentlicht, über der sie gemessen wurde.
Lies die beiden Enden dieser Tabelle zusammen, denn die Spreizung ist der
nützliche Teil. Bei Lovable sind es 8 Apps von 18.518, bei v0 überhaupt keine.
Diese Apps haben keinen kleinen eigenen Server: die Seite spricht direkt aus dem
Browser mit Supabase, es gibt also nirgends ein /api/… von dir, das diese
Prüfung finden könnte. Was die Daten in so einer App schützt, sind die Regeln
auf jeder Tabelle, und das ist ein anderer Befund mit einer
eigenen Art, schiefzugehen.
Wann das JSON Einstellungen sind und wann Personen
Eine Frage entscheidet: beschreibt irgendetwas in der Antwort eine Person?
Einstellungen beschreiben deine App. Ein Flag dafür, ob der Dunkelmodus an ist, die Liste der Währungen, die du annimmst, die Version von irgendetwas, der Text für ein Cookie-Banner. Das zu veröffentlichen verrät, wie deine App konfiguriert ist, und deine App läuft ohnehin vor aller Augen.
Zeilen beschreiben deine Nutzer. Ein Name, eine E-Mail-Adresse, was jemand gekauft hat, was er geschrieben hat, wo er wohnt. Das ist kein Satz über eine Konfiguration, das ist der Inhalt des Aktenschranks, und es zählt deshalb, weil es so alltäglich ist, ihn mitzunehmen. Es gibt keinen Einbruch. Die Adresse ist eine Textzeile, die in jedem Browser funktioniert, also wird sie in einen Gruppenchat kopiert, in jemandes Notizen gespeichert und von einem Skript, das niemand beobachtet, im Takt abgerufen.
Einen schließen, und warum Umbenennen ihn nicht schließt
Verlange an der Adresse einen Login, und antworte einem Aufrufer, der keinen hat, mit einer 401.
Das ist die ganze Behebung, und sie gehört an die Adresse und nirgendwo sonst. Drei Dinge, die wie die Behebung aussehen und keine sind:
- Den Pfad umbenennen oder ihn aus deinem Code nehmen. Bei diesem ist Vorsicht geboten, weil der Befund verschwindet. Wer die URL schon hatte, hat sie weiterhin, sie steht in Browser-Verläufen und Server-Logs, und der Aktenschrank ist immer noch offen, nur ohne Schild an der Front.
- Deinen CORS-Header verengen. Der regelt, welche anderen Websites eine Antwort im Browser von jemandem lesen dürfen, und sonst schaut ihn nichts an. Ein Skript oder ein Terminal liest dieselbe Adresse so oder so, weshalb der Wildcard-Befund eine andere Frage ist.
- In der App filtern. Wenn die Seite die Zeilen versteckt, die sie nicht zeigen soll, schickt die Adresse sie trotzdem. Gefiltert werden muss, bevor die Antwort hinausgeht.
Es gibt eine vierte Möglichkeit, und auf einer öffentlichen Seite ist sie oft die beste: den Endpunkt abschaffen. Wenn die Daten ohnehin nur für deine eigene Seite sind, kann die Seite sie beim Bauen bekommen, und die Adresse verschwindet dabei aus deinem Code.
Wie die Behebung im Code aussieht
Zwei Dinge, im Handler, der die Adresse beantwortet: herausfinden, wer fragt, und aufhören, wenn die Antwort niemand lautet.
Vielleicht tippst du das nie selbst, und das ist in Ordnung. Lies es trotzdem, denn daran prüfst du, ob dein Builder wirklich getan hat, worum du ihn gebeten hast. Das hier ist die Form davor, und das ist, was der Scan gefunden hat:
app.get('/api/orders', async (req, res) => {
const orders = await db.orders.findMany()
res.json(orders)
})
Und danach:
app.get('/api/orders', async (req, res) => {
const user = await getUserFromRequest(req)
if (!user) {
return res.status(401).json({ error: 'Not signed in' })
}
const orders = await db.orders.findMany({ where: { userId: user.id } })
res.json(orders)
})
Zwei Dinge haben sich geändert, und beide zählen. Die 401 ist die Tür. Das
where ist der Grund, warum sich die Tür lohnt: ohne es kann ein angemeldeter
Besucher die Bestellungen aller anderen Kunden lesen, was ein kleineres Publikum
für dieselben Daten ist und immer noch das falsche.
Bei Supabase Edge Functions lies erst die Konfiguration, bevor du irgendetwas
schreibst. Edge Functions prüfen das Token des Aufrufers von sich aus: die
Konfigurationsreferenz von Supabase setzt verify_jwt standardmäßig auf true,
eine Funktion, die Fremden antwortet, ist also eine, bei der das jemand
abgeschaltet hat, entweder mit einer Zeile in supabase/config.toml oder beim
Deployen mit --no-verify-jwt:
[functions.orders]
verify_jwt = false
Wenn deine Funktion privat sein soll, lösche diese zwei Zeilen und deploye neu. Lass sie nur dort stehen, wo der Endpunkt wirklich jedem antworten muss, und das ist der Fall, den die Dokumentation von Supabase selbst als Beispiel nimmt: ein Zahlungs-Webhook. Innerhalb der Funktion gibt dir das aktuelle SDK einen Client, der bereits auf die Person zugeschnitten ist, die aufgerufen hat:
import { withSupabase } from 'npm:@supabase/server'
export default {
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
const { data } = await ctx.supabase.from('orders').select()
return Response.json(data)
}),
}
ctx.supabase läuft als der Aufrufer, deine Row-Level-Security-Regeln
entscheiden also, was zurückkommt, und das ist derselbe Schutz, auf den sich der
Rest deiner App verlässt, sowie
die Sache, die man getrennt prüfen sollte.
Der Prompt zum Einfügen in deinen Builder
Wenn du in Lovable, Bolt, Cursor, Replit oder v0 baust, gib ihm das hier. Lass es auf Englisch, in welcher Sprache du das hier auch liest, denn in dieser Sprache denken diese Werkzeuge, und ersetze die beiden Teile in Klammern durch das, was dein eigener Bericht sagt:
A security scan of [my-app.com] found these API endpoints answer
without any authentication: [/api/orders, /api/users].
Please look at each one and decide whether it is meant to be public.
For the ones that are not, require a valid session or API token and
return 401 otherwise. Make sure each one returns only the rows that
belong to the person asking, not the whole table filtered in the UI.
For any that must stay open, make sure they return only non-sensitive
data and add rate limiting so they cannot be abused.
Tell me what you changed for each endpoint, and do not rename or
remove the paths.
Der letzte Satz steht dort mit Absicht. Wird ein Modell gebeten, einen Befund verschwinden zu lassen, nimmt es manchmal den kürzesten Weg und verschiebt die Adresse, und das ist das eine Ergebnis, das beim erneuten Scan wie Erfolg aussieht und nichts ändert.
Was du jetzt tun solltest
Was zu tun ist
- Öffne jede gemeldete Adresse in einem privaten Browserfenster und lies, was zurückkommt. Das ist der Schritt, den der Bericht dir nicht abnehmen kann.
- Sind es Einstellungen und ist die Adresse eine, die du nie geschrieben hast, gehört sie deinem Builder und es gibt nichts zu beheben. Prüfe den Pfad in der Doku deiner Plattform, bevor du Geld dafür ausgibst.
- Enthält die Antwort einen Namen, eine E-Mail oder eine Bestellung, verlange an dieser Adresse noch heute einen Login und gib jedem ohne Login eine 401 zurück.
- Benenne den Pfad nicht um und lösche den Verweis darauf nicht. Der Befund verschwindet, und die Adresse antwortet weiter.
- Ändere in deiner eigenen App eine ID in der URL. Eine Adresse, die einem Fremden einen Datensatz gibt, gibt ihm meist alle.
Die Adressen auf dieser Liste hat jemand geschrieben, der damals wusste, was dahinter lag, und was sich ändert, ist das, was dahinter liegt. Reeve Care führt diesen Scan nach einem Zeitplan erneut gegen deine Live-App aus und schickt dir eine E-Mail, wenn ein Ergebnis schlechter wird, und genau diesen Fall kann der abgemeldete Durchgang oben nicht fangen: was Care überwacht und was es kostet.
Wenn du lieber alles in einem Durchgang abarbeitest: die Sicherheits-Checkliste in 10 Minuten deckt das hier neben allem anderen ab, was eine frisch gestartete App gern offen lässt, und welche Schlüssel im Frontend sicher sind ist der andere Befund, mit dem Leute meistens ankommen.
FAQ
Was bedeutet "offener API-Endpunkt" in meinem Bericht?
Es bedeutet, dass wir den Code gelesen haben, den deine App an einen Browser schickt, darin eine Adresse gefunden haben, von der deine App Daten holt, und diese Adresse ohne Konto und ohne Login nach Daten gefragt haben. Sie hat geantwortet, und die Antwort war JSON. Das ist der ganze Befund. Er hält fest, was passiert ist, und urteilt nicht darüber, ob die Daten privat waren, denn das kann nichts außerhalb deiner App wissen.
Ist jeder offene API-Endpunkt ein Sicherheitsproblem?
Nein. Viele Adressen sollen jedem antworten: eine veröffentlichte Preisliste, ein Artikel, eine Liste der aktivierten Funktionen. Das Problem ist die Adresse, die Datensätze von Personen herausgibt, denn das tut sie für jeden, der die URL hat. Lies, was zurückkam, und frage dich, ob irgendetwas davon eine Person beschreibt.
Mein Bericht meldet einen Endpunkt, den ich nie geschrieben habe. Was ist das?
Meist einer deines Builders. Plattformen, die deiner App einen kleinen eigenen Server geben, legen auch ein paar eigene Adressen hinein, und die stecken im Code jeder App auf dieser Plattform. Das klarste Beispiel, das wir gemessen haben, sind die Cookie-Einstellungen von Base44 unter /api/consent/config, auf die 2.705 der 3.852 Befunde unseres Sweeps vom August 2026 entfallen. Sie geben Einstellungen zurück, sie sind auf jeder Base44-App gleich, und nichts darin gehört dir.
Wie prüfe ich, was die Endpunkte meiner App zurückgeben?
Öffne deine Live-App, drücke F12, klicke auf Netzwerk und lade neu. Die Anfragen, die als JSON zurückkommen, sind die Adressen, von denen deine App Daten holt. Kopiere jede URL, öffne ein privates Browserfenster, damit du abgemeldet bist, und füge sie einzeln ein. Lies, was ankommt. Ein Fehler oder eine leere Liste ist in Ordnung. Zeilen mit Namen, E-Mail-Adressen oder Bestellsummen kann jeder lesen, der diese Adresse hat.
Reicht es, den Pfad zu verstecken?
Nein. Die Adresse umzubenennen oder den Verweis darauf aus deinem Code zu nehmen, hält einen Scanner vom Finden ab und lässt sie genauso antworten wie vorher. Wer die URL schon hatte, hat sie weiterhin, und sie bleibt in Browser-Verläufen, Server-Logs und allem, was deine Seite gecrawlt hat. Behoben wird es an der Adresse: einen Login verlangen und einem Fremden mit einer 401 antworten.