← Zurück zum Blog
Vibe CodingScanaris Team · 5 Min. Lesezeit · October 04, 2026

Sicherheit beim Deployen auf Vercel

Vercel macht das Deployen so einfach, dass man vergisst, dass es immer noch ein Server im Internet ist. Die Plattform selbst ist gut geschützt: automatisches TLS, globales Netz, Isolation zwischen Projekten. Die Löcher baust du selbst in die Konfiguration, und es sind fast immer dieselben fünf oder sechs. Dieser Guide geht sie einzeln durch, mit dem Befehl zum Prüfen und der exakten Änderung zum Schließen, gedacht für Apps, die mit Cursor, Bolt oder v0 erzeugt wurden und auf Vercel landen.

1. Umgebungsvariablen, die im Browser landen

Bei Vercel definierst du die Variablen im Projekt-Dashboard, und das Framework entscheidet, welche zum Client gelangen. In Next.js alles, was mit NEXT_PUBLIC_ beginnt; in Vite mit VITE_; in Nuxt alles unter runtimeConfig.public. Eine nützliche Konvention, bis jemand NEXT_PUBLIC_STRIPE_SECRET_KEY setzt, weil die KI aus einer Komponente darauf zugreifen musste. Dieser Schlüssel reist im Bundle zu allen Besuchern.

Zwei Gewohnheiten verhindern das. Erstens: das Präfix prüfen. Hat eine Variable das öffentliche Präfix, geh davon aus, dass sie öffentlich ist, und frag dich, ob sie das sein sollte. Zweitens: die Vercel-Umgebungen (Production, Preview, Development) nutzen, damit Produktionsschlüssel in Testbranches nicht existieren, und sensible als Sensitive markieren, womit man sie später im Dashboard nicht mehr einsehen kann. So prüfst du, was im Bundle gelandet ist:

curl -s https://deinedomain.com/ | grep -o '/_next/static/chunks/[^"]*\.js' | sort -u | head -20

Lade diese Dateien herunter und such nach sk_live, service_role, AKIA oder den Namen deiner Variablen. Mehr in Geheimnisse, die deine App im Browser preisgibt.

2. Öffentliche Preview-Deployments

Jeder Branch und jeder Pull Request erzeugt eine URL wie projekt-git-branch-team.vercel.app. Praktisch, um Änderungen zu zeigen, und öffentlich: Jeder mit der URL sieht die Entwicklungsversion, mit halbfertigen Funktionen und manchmal Testdaten. Vercel setzt standardmäßig einen Header, damit Suchmaschinen Previews nicht indexieren, aber das hindert keine Person daran, sie zu öffnen.

Die Lösung liegt unter Settings, Deployment Protection: Aktiviere Vercel Authentication, damit nur Teammitglieder auf Previews zugreifen (im kostenlosen Plan verfügbar), oder den Passwortschutz in den Bezahlplänen. Und denk daran, dass die Produktions-URL projekt.vercel.app neben deiner Domain ebenfalls existiert: Leite sie auf deine Domain um oder setz eine Canonical, damit sie bei Google nicht mit dir konkurriert.

3. Sicherheits-Header, die niemand gesetzt hat

Vercel liefert deine App mit den minimalen Headern aus; die Sicherheits-Header musst du selbst hinzufügen. Ohne sie kann deine Website in einen fremden iframe eingebettet werden, der Browser rät Inhaltstypen, und es gibt keine Richtlinie, die einschränkt, welche Skripte laufen. In der vercel.json fügst du sie so hinzu:

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "X-Frame-Options", "value": "DENY" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
      ]
    }
  ]
}

In Next.js geht das auch über die next.config.js mit der Funktion headers(). Die Content-Security-Policy verdient einen eigenen Schritt, weil sie auf deine Skripte abgestimmt werden muss; jeden Header erklärt HTTP-Sicherheits-Header für Menschen erklärt, und deine prüfst du mit dem Header-Analyzer.

4. Veröffentlichte Source Maps

Source Maps zeigen den Originalcode statt des minifizierten. Zum Debuggen nützlich, in Produktion eine schlechte Idee: Sie verschenken deine Logik, deine internen Routen und die Kommentare mit „TODO: diesen Schlüssel entfernen". Next.js deaktiviert sie im Browser standardmäßig (productionBrowserSourceMaps: false); in Vite hängt es von build.sourcemap ab, das manche Templates auf true setzen. Prüf, ob sie existieren:

curl -sI https://deinedomain.com/_next/static/chunks/main-abc123.js.map | head -1

Antwortet es mit 200, sind sie veröffentlicht. Brauchst du Maps für das Fehler-Tracking, lade sie beim Build zu deinem Monitoring-Dienst hoch und liefere sie nicht öffentlich aus.

5. Dateien und Routen, die nicht antworten sollten

Alles im Ordner public/ wird unverändert ausgeliefert. Eine versehentlich dorthin kopierte .env, eine backup.json, eine config.yml mit Zugangsdaten: öffentlich. API-Routen zählen auch: /api/debug, /api/seed oder /api/admin, die die KI zum Testen angelegt hat und die ohne Authentifizierung in Produktion geblieben sind. Und Cron-Routen: Vercel ruft sie mit einem Authorization-Header auf, der dein CRON_SECRET enthält; prüfst du ihn im Code nicht, kann jeder deine geplante Aufgabe auslösen.

for p in .env .env.local .git/config config.json backup.zip api/debug api/seed; do
  printf "%s -> " "$p"; curl -s -o /dev/null -w "%{http_code}\n" "https://deinedomain.com/$p"
done

Alles, was mit 200 antwortet, verdient einen Blick.

6. Functions ohne Limits

Eine API-Route, die OpenAI aufruft oder E-Mails versendet, ohne Anfragen zu begrenzen, ist eine Rechnung, die darauf wartet, entdeckt zu werden. Vercel hat eine Firewall mit Rate-Limit-Regeln pro IP und einen Challenge-Modus gegen Bots, den du im Dashboard aktivierst, ohne Code anzufassen. Für kostenpflichtige Endpunkte ergänze zusätzlich ein Limit pro Nutzer in deiner eigenen Logik und verlange eine Sitzung.

7. CORS und Cookies auf API-Routen

Antwortet deine API mit Access-Control-Allow-Origin: * und nutzt zusätzlich Cookies, kann jede Website im Namen deiner Nutzer Anfragen stellen. Bei Vercel konfigurierst du das pro Route in der vercel.json oder im Handler selbst. Liste die erlaubten Origins explizit auf und kombiniere nie den Platzhalter mit Credentials. Details in falsch konfiguriertes CORS.

8. Was Vercel schon für dich erledigt

Damit du keine Zeit verlierst: Das TLS-Zertifikat wird automatisch ausgestellt und erneuert, HTTP leitet automatisch auf HTTPS um, Functions laufen isoliert, und Deployment-Logs werden protokolliert. Was es nicht tut: für dich entscheiden, was öffentlich ist, welche Header du sendest oder wer deine Previews sehen darf. Dieser Teil gehört dir.

Fünf-Minuten-Checkliste

  • Keine Variable mit öffentlichem Präfix enthält einen geheimen Schlüssel.
  • Deployment Protection für Previews aktiviert.
  • Sicherheits-Header in vercel.json oder next.config.js.
  • Source Maps in Produktion nicht erreichbar.
  • Nichts Sensibles in public/; Testrouten entfernt; Cron mit seinem Secret geschützt.
  • Rate-Limit auf kostenpflichtigen Routen.
  • CORS mit expliziten Origins.
  • Die .vercel.app-URL leitet auf deine Domain um.

Scanaris prüft es für dich

Scanaris prüft dein Vercel-Deployment von außen: Header, Geheimnisse im Bundle, Source Maps, offengelegte Dateien und Routen, CORS, Cookies und TLS, und gibt dir pro Fehler einen Fix-Prompt zum Einfügen in Cursor, Bolt oder v0 mit der exakten Änderung in der vercel.json oder in deinem Code. Das sind reine Lesezugriffe auf das, was schon öffentlich ist; dein Projekt wird nie angefasst. Die plattformspezifischen Risiken stehen im Sicherheits-Guide für Vercel, und wenn deine App Next.js ist, in der Next.js-Checkliste.

Häufige Fragen

Sind Vercel-Previews standardmäßig privat?

Nein. Sie sind für jeden mit der URL öffentlich, auch wenn Suchmaschinen sie nicht indexieren. Aktiviere Vercel Authentication unter Deployment Protection, um sie auf dein Team zu beschränken.

Setzt Vercel Sicherheits-Header automatisch?

Nur die grundlegenden Betriebs-Header. HSTS, X-Frame-Options, Content-Security-Policy und den Rest musst du selbst in der vercel.json oder im Framework konfigurieren.

Was, wenn ein geheimer Schlüssel schon mit öffentlichem Präfix veröffentlicht wurde?

Betrachte ihn als kompromittiert, auch wenn du ihn aus dem Code entfernst: Das vorherige Bundle kann gecacht oder heruntergeladen sein. Rotiere den Schlüssel beim Ursprungsdienst, verschieb ihn in eine Variable ohne Präfix und deploye neu.

Wie steht deine Website da?

Lass Scanaris drüberlaufen und prüf es in 30 Sekunden, kostenlos.

Meine Website scannen

Verwandte Checks

Sicherheits-Guides für deinen Stack