FixVibe

// docs / security guides / hardening

So sicherst du eine App, die mit KI-Coding-Tools gebaut wurde

Eine Schritt-für-Schritt-Anleitung zum Härten von Apps, die Sie mit Cursor, Claude Code, Lovable, Bolt, v0, Replit oder Windsurf erstellt haben. Vier Phasen: Verstehen Sie, warum AI-generierte Apps unterschiedlich ausfallen, führen Sie ein sofortiges Codebasis-Audit durch, härten Sie es zum Zeitpunkt der Bereitstellung aus und führen Sie dann die Überwachung fort. Meinungsstark, erzählerisch, mit echten Ausschnitten zum Nachmachen.

Warum AI-generierte Apps unterschiedlich scheitern

Vibe-codierte Apps können sicher sein. Sie benötigen einen zusätzlichen Prüfdurchgang, da die Fehlerarten struktureller und nicht unachtsamer Natur sind:

  • Assistants inline hardcoded keys. You ask for a fix to an auth error and get a pasted Supabase example that assumes a service-role client. The key ends up at the top of a page component. Both the anon client and the service client coexist; both ship.
  • Generated servers default to permissive CORS. Generated Express / Fastify handlers often ship with cors({ origin: '*' }) because that's the fastest way to get a working preview. The middleware never gets a second pass.
  • Rules files get skipped. Firestore-backed projects generate the data model but rarely touch firestore.rules. Test-mode rules let anyone read and overwrite data until someone replaces them.
  • RLS never enters the migration. A generated Supabase schema and CRUD surface use the anon key, but ENABLE ROW LEVEL SECURITY never enters the migration. Anonymous users can read or write any row.
  • Handlers trust IDs. A generated GET /api/items/[id] reads the param and queries Postgres without verifying ownership. Active scans on a verified domain test for this (IDOR / BOLA).

Die unmittelbare Prüfung: Durchsuchen Sie Ihre Codebasis nach Risikomustern

Bevor Sie etwas aushärten, finden Sie heraus, was bereits kaputt ist. Diese Greps dauern jeweils weniger als eine Minute:

Geheimnisse und Anbieterschlüssel

bash
grep -RIn 'NEXT_PUBLIC_SUPABASE_SERVICE' src/
grep -RIn 'sk_live_\|pk_live_\|STRIPE_SECRET' src/
grep -RIn 'sk-ant-\|^sk-' src/  # Anthropic / OpenAI
grep -RIn 'AIza\|AKIA' src/        # Google / AWS
grep -RIn 'eyJh[A-Za-z0-9_-]\{20,\}' src/  # JWT-shaped strings

Jeder Treffer erfordert eine Löschung plus Schlüsselrotation. Provider-Dashboards: Supabase → Einstellungen → API, Stripe → Entwickler → API Schlüssel, Anthropic / OpenAI-Konsole.

Datenbankzugriffskontrollen

bash
# Supabase migrations
grep -RIn 'CREATE TABLE public\.' supabase/migrations/
grep -RIn 'ENABLE ROW LEVEL SECURITY\|FORCE ROW LEVEL SECURITY' supabase/migrations/

# Firebase / Firestore
cat firestore.rules  # confirm no `if true;` matches

Jedes CREATE TABLE public.* benötigt ein passendes ENABLE ROW LEVEL SECURITY und mindestens eine Richtlinie. Firestore-Regeln müssen den Lesebereich auf request.auth.uid beschränken.

Authentifizierungs- und Sitzungsverwaltung

bash
grep -RIn 'getSession()' src/   # should be getUser() server-side
grep -RIn 'localStorage\.\(set\|get\)Item.*token' src/
grep -RIn 'jwt.verify.*\(noVerify\|skipVerify\)' src/

Vom Server gerenderte Routen müssen supabase.auth.getUser() verwenden – die Überprüfung erfolgt mit dem Backend. getSession() liest ein nicht verifiziertes Cookie. Auf Token in localStorage kann jedes Skript zugreifen, das auf der Seite ausgeführt wird.

Header und Middleware

bash
# Confirm middleware location for src/ layouts
ls src/middleware.ts middleware.ts 2>&1

# Look for CSP and security headers
grep -RIn 'Content-Security-Policy\|Strict-Transport-Security' src/

Beim src/-Layout wird nur src/middleware.ts aufgenommen. Wenn sich Ihre Middleware-Datei im Projektstammverzeichnis befindet, wird sie von Next.js stillschweigend ignoriert und Ihre CSP / auth-refresh-Logik wird nie ausgeführt.

Verhärtung zum Zeitpunkt der Bereitstellung

Sobald die Quelle bereinigt ist, sperren Sie, wie die App in die Produktion gelangt.

Schritt 1: Separate Umgebungen

Vercel: drei Umgebungen – Production (Ihre Produktionsdomäne), Vorschau (PR / Staging-Bereitstellungen), Entwicklung (lokal). Jeder erhält seinen eigenen Env-Var-Satz. Live Stripe / Anthropic / Supabase Keys erreichen nie die Vorschau; Vorschauschlüssel erreichen nie Production. Zweige werden automatisch in die Vorschau verschoben; Zusammenführen zu main wird zu Production bereitgestellt.

Schritt 2: Striktes CSP über Middleware

Generieren Sie eine Nonce pro Anfrage und fügen Sie sie dann in Content-Security-Policy ein. Next.js wendet die Nonce automatisch auf seine eigenen Skript-Tags an, wenn Sie den x-nonce-Anforderungsheader festlegen.

ts
// src/middleware.ts
import { NextResponse, type NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const nonce = crypto.randomUUID().replace(/-/g, '');
  const csp = [
    `script-src 'nonce-${nonce}' 'strict-dynamic'`,
    `style-src 'self' 'unsafe-inline'`,
    `img-src 'self' data: https:`,
    `connect-src 'self' https://*.supabase.co`,
    `object-src 'none'`,
    `base-uri 'self'`,
    `frame-ancestors 'none'`,
  ].join('; ');

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set('Content-Security-Policy', csp);
  response.headers.set('X-Content-Type-Options', 'nosniff');
  response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  return response;
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};

Schritt 3: Erzwingen Sie RLS für jede öffentliche Tabelle

RLS isn't enabled by default on tables you create in SQL or migrations. Enable it on every exposed table and pair each one with explicit policies per role — that is what stops the anon and authenticated roles. FORCE only makes the table owner obey RLS too.

sql
-- supabase/migrations/XXXX_rls.sql
alter table public.profiles enable row level security;
alter table public.profiles force row level security;

create policy "profiles: read own"
  on public.profiles for select
  using (auth.uid() = id);

create policy "profiles: update own"
  on public.profiles for update
  using (auth.uid() = id)
  with check (auth.uid() = id);

Schritt 4: Nur-Server-Authentifizierungsüberprüfung auf jeder API-Route

Jede zustandsverändernde API-Route verifiziert den Aufrufer serverseitig mit supabase.auth.getUser(). Das Benutzerobjekt wird zur Quelle der Wahrheit für user_id – vertrauen Sie niemals einem Anforderungstext, der es festlegt.

ts
// src/app/api/items/route.ts
import { NextResponse, type NextRequest } from 'next/server';
import { createClient } from '@/lib/supabase/server';

export async function POST(request: NextRequest) {
  const supabase = await createClient();
  const { data: { user } } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: 'unauthorized' }, { status: 401 });

  const body = await request.json();
  const { data, error } = await supabase
    .from('items')
    .insert({ ...body, user_id: user.id })  // server-supplied, not from body
    .select()
    .single();

  if (error) return NextResponse.json({ error: error.message }, { status: 400 });
  return NextResponse.json(data);
}

Schritt 5: Reverse-Proxy Ihrer Analysen

Proxying-Analysen über Ihre eigene Domain vermeiden Werbeblocker und sorgen dafür, dass Ihr CSP connect-src 'self' eng bleibt. Das gleiche Muster funktioniert für PostHog, Plausible, Umami und benutzerdefinierte Ereignissenken.

ts
// src/app/api/posthog/[...path]/route.ts
import { type NextRequest } from 'next/server';

const UPSTREAM = 'https://us.i.posthog.com';

export async function POST(req: NextRequest, { params }: { params: Promise<{ path: string[] }> }) {
  const { path } = await params;
  const url = `${UPSTREAM}/${path.join('/')}`;
  return fetch(url, {
    method: 'POST',
    headers: { 'content-type': req.headers.get('content-type') ?? 'application/json' },
    body: await req.text(),
  });
}

Schritt 6: Öffnen Sie den Redirect-Schutz für den Post-Authentifizierungs-Bounce

Anmelde-/Registrierungsabläufe akzeptieren üblicherweise einen next-Abfrageparameter. Lehnen Sie alles ab, was kein Pfad zur gleichen Site ist – beginnen Sie mit / und niemals mit // (protokollbezogen, leitet Benutzer von der Site ab).

ts
function safeNext(raw: string | null): string {
  if (!raw) return '/dashboard';
  if (!raw.startsWith('/') || raw.startsWith('//')) return '/dashboard';
  return raw;
}

Laufend: Überwachung und erneutes Scannen

Bei jedem Einsatz kommt es zu Drift. Behandeln Sie Sicherheit als eine Schleife und nicht als eine Checkliste, die Sie durcharbeiten.

Überprüfen Sie Ihre Produktionsdomäne

Dashboard → Domains → add your production domain → DNS TXT or HTTP-file verification. Active scans require Hobby or above; scheduled re-scans require Pro or Unlimited.

Planen Sie passive erneute Scans

Scheduled re-scans are available on Pro and Unlimited for verified domains. Free and Hobby scans are manual. Scheduled scans use your plan allowance. Configure completion email preferences and a scan.completed webhook if needed.

bash
# Or from CI, via the REST API:
curl -X POST https://fixvibe.app/api/v1/scans \
  -H "authorization: Bearer $FIXVIBE_TOKEN" \
  -H "content-type: application/json" \
  -d '{"target":"https://your-app.com"}'

API-aktive Scans aktivieren (optional)

Wenn Sie eine automatisierte aktive Prüfung (SQLi / XSS / IDOR Gehen / usw.) wünschen, schalten Sie sie pro Domäne unter Dashboard → Domänen → API aktiv ein. Die Autorisierung ist dauerhaft, läuft 90 Tage ab und kann sofort widerrufen werden. Koppeln Sie es mit dem scan.active_api.first_used-Webhook, damit der erste automatisierte aktive Scan nach der Aktivierung Ihre Benachrichtigung erreicht.

Integrieren Sie die Ergebnisse in Ihren AI Workflow

On Hobby or above, create an API token at Account → API tokens and configure the MCP server (/docs/mcp) in your coding tool. Ask your agent to run an authorized scan and inspect the highest-severity findings. Code fixes can use remediation prompts; provider and DNS fixes may need manual operator steps.

Live-Bedrohungserkennung (Unlimited)

Periodic certificate-transparency, DNS, JS-bundle, and threat-intelligence checks report observed changes on supported signals. Alerts depend on successful polling and source availability; they do not establish continuous or complete security coverage.

Echte Fehlermuster und deren Behebung

Five common patterns in AI-generated apps, each with the actual fix:

  1. Dienstrollenschlüssel in einer Clientkomponente

    Symptom: FixVibe reports an exposed Supabase service-role key on the production URL. Cause: an autocomplete pasted createClient(URL, SERVICE_ROLE_KEY) into a React component. Fix: move the service client to src/lib/supabase/service.ts with import 'server-only' at the top; create a parallel src/lib/supabase/client.ts using the anon key for client-side use; rotate the service-role key via Supabase Studio.

  2. Firestore-Regeln bleiben im Testmodus

    Symptom: a high-severity open Firebase rules finding. Cause: generated rules read allow read, write: if request.time < timestamp.date(2026, 6, 1); — a time-bounded "allow all". Fix: scope each rule to the authenticated user — match /users/{userId}/posts/{postId} { allow read, write: if request.auth.uid == userId; } — and re-deploy firebase deploy --only firestore:rules.

  3. Freizügiges CORS Überleben in der Produktion

    Symptom: a high-severity CORS misconfiguration finding. Cause: generated Express middleware: app.use(cors({ origin: '*' })). Fix: allowlist your frontend origin: app.use(cors({ origin: ['https://your-app.com'], credentials: true })). For Next.js API routes, set Access-Control-Allow-Origin explicitly in the response.

  4. RLS aktiviert, aber nicht erzwungen

    Symptom: FixVibe reports that anonymous visitors can read a public table even though RLS looks enabled in the dashboard. Cause: RLS is on, but a policy such as USING (true) lets the anon role through, or the migration that tightened it never ran in production. Fix: replace the permissive policy with one scoped to auth.uid(), apply the migration, and re-scan.

  5. Nicht signierte IDOR-begehbare IDs

    Symptom: an active scan on your verified domain reports that one user can read another user's records at /api/items/1, /api/items/2, ... Cause: the API handler trusts the path param and queries Postgres without an ownership predicate. Fix: add .eq('user_id', user.id) on every read query, or move to signed URLs / UUIDs scoped under /api/users/[uid]/items/[id].

Die Vibe-Code-Sicherheitsschleife

Das Ziel ist nicht perfekte Sicherheit; Es eliminiert die niedrig hängenden Früchte, die AI Tools ständig übersehen, sodass Sie weiterhin schnell versenden können.

  1. Generate fast – verwenden Sie Cursor, Claude Code, Lovable, Bolt. Das ist der Punkt.
  2. Audit immediately – Führen Sie den oben angegebenen grep-Satz aus, überprüfen Sie RLS, überprüfen Sie CSP und überprüfen Sie die Authentifizierungsgrenze.
  3. Harden at deploy – Middleware, Umgebungstrennung, CSP Nonce, HSTS, reine Server-Authentifizierungsüberprüfung.
  4. Monitor – FixVibe täglich passiv, wöchentlich aktiv auf einer verifizierten Domain, Webhooks zu Slack, Bedrohungserkennung auf Unlimited.
  5. Fix fast — use FixVibe coding-agent prompts for code/config findings and operator steps for DNS, provider, secret-rotation, or manual-review findings. Re-deploy, re-scan, close the loop.

Nächste Schritte

Für den konzeptionellen Hintergrund zu DAST vs. SAST und warum AI-generierte Apps einen eigenen Scan benötigen, lesen Sie AI-generated code security scanning. Eine Kurzreferenz vor dem Versand finden Sie im vibe coding security checklist.

// deine App scannen

Genug gelesen. Finde die Lücken in deiner App.

Drop in a URL — FixVibe runs every passive check from this guide plus the rest of its 230+ passive checks, usually in under a minute. Free, no install, no card.

  • Free-Tier — 3 Scans / Monat, ohne Karte.
  • Passive Scans gegen jede URL — keine Domain-Verifizierung nötig.
  • Abgestimmt auf Cursor, Claude Code, Lovable, Bolt, v0, Replit.
  • Coding-agent prompts for code/config findings, plus operator steps for DNS/provider fixes.
Kostenlosen Scan starten →

keine Anmeldung nötig

So sicherst du eine App, die mit KI-Coding-Tools gebaut wurde · FixVibe