
Scanner di sicurezza statico locale per app Next.js, Supabase e Stripe: 24 controlli basati su AST per chiavi esposte, RLS e grant mancanti, webhook non sicuri. CLI e GitHub Action.
Scansione di sicurezza locale e gratuita per app Next.js + Supabase + Stripe: chiavi esposte, RLS e grant mancanti, webhook Stripe non sicuri.
Il tuo agente AI ha rilasciato l'app. Ha anche rilasciato la tua chiave segreta Stripe, una tabella senza RLS o un webhook che chiunque può chiamare? Un solo comando lo scopre, in locale, in meno di un secondo.
npx github:edtrackai/nextjs-supabase-stripe-security-checker /path/to/your/app
Non è ancora su npm, quindi npx lo esegue direttamente da questo repository GitHub (richiede Node 18+ e git).
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0
with:
fail-on: high
Il flusso di lavoro completo e i permessi sono riportati di seguito e in docs/github-action.md.
Verifica RLS di Supabase · Sicurezza dei webhook Stripe · Scansione di sicurezza Next.js · Concessioni dell'API Data di Supabase (42501)

git clone https://github.com/edtrackai/nextjs-supabase-stripe-security-checker.git
cd nextjs-supabase-stripe-security-checker && npm install
node bin/nss-security-check.js /path/to/your/app
Node 18 o successivo. C'è una sola dipendenza (@babel/parser). È gratuito e con licenza MIT, non richiede alcun account, non effettua chiamate di rete e non carica mai il tuo codice.
--fail-on=high esce con 1, e --json fornisce output leggibile dalla macchina.Annuncio (a pagamento, stesso autore): Vuoi le correzioni? Launch Audit (12 $ più IVA ove applicabile) aggiunge 28 controlli, un agente auditor AI senza strumenti Edit o Write, e un piano di correzione file:riga.
| Flag | Cosa fa |
|---|---|
--json | Output leggibile dalla macchina: {tool, version, root, filesScanned, counts, findings[]} |
--fail-on=<sev> | Esce con 1 se un risultato è pari o superiore a critical / high / medium / low (none non fallisce mai). Esce con 2 in caso di argomenti errati. |
--list | Stampa il catalogo dei controlli |
--quiet | Omette il piè di pagina di una riga sugli strumenti a pagamento (stampato su stderr solo su un terminale; disattivato anche con NO_PROMO=1, CI o GITHUB_ACTIONS) |
--help | Utilizzo |
In CI: node path/to/bin/nss-security-check.js . --fail-on=high, oppure usa la GitHub Action (riepilogo del job, annotazioni, un commento sticky sulla PR, solo GITHUB_TOKEN). Vedi il workflow di esempio e i permessi in docs/github-action.md.
# .github/workflows/security-check.yml
name: Security check
on: [pull_request]
permissions:
contents: read
pull-requests: write # only for the PR comment; drop it with comment: false
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0 # or pin @v0.5.0 / a commit SHA
with:
path: .
fail-on: high
Le modifiche sono elencate in CHANGELOG.md (la 0.5.0 aggiunge l'Action).
| ID | Gravità | Area | Controllo |
|---|---|---|---|
| K1 | critica | Chiavi | Chiave segreta/limitata Stripe live (sk_live_/rk_live_) nel codice sorgente, incluse le chiavi suddivise con + (l'evidenza è oscurata) |
| K2 | critica | Chiavi | Variabile NEXT_PUBLIC_ dall'aspetto segreto (service role, secret key, webhook secret…) |
| K3 | critica | Chiavi | File .env con valori tracciati da git |
| K4 | critica | Chiavi | Segreto lato server o client admin Supabase usato in un componente "use client" |
| A1 | alta | Auth | auth.getSession() considerato attendibile sul server invece di getUser()/getClaims() |
| A2 | alta | Auth | Server Action che scrive dati senza controllo di autenticazione |
| A3 | alta | Auth | Route API (POST/PUT/PATCH/DELETE) che scrive dati senza controllo di autenticazione (route webhook, cron e auth escluse) |
| A4 | alta | Auth | Client admin interrogato con un id fornito dalla richiesta senza filtro sul proprietario (IDOR) |
| A5 | media | Auth | Open redirect da un parametro di query |
| R1 | critica | RLS | Tabella creata senza row level security |
| R2 | critica | RLS | Policy di scrittura con using (true) / with check (true) |
| R3 | alta | RLS | Policy che consente al ruolo anon di scrivere |
| R4 | alta | RLS | Funzione security definer senza search_path fisso |
| R5 | media | RLS | Tabella in public senza GRANT esplicito. Supabase ha annunciato che smetterà di concedere i grant predefiniti sulle nuove tabelle pubbliche a partire dal 30 ott 2026, ma a fine agosto un maintainer della CLI di Supabase ha scritto (supabase/cli PR #6337) che la precedente modifica predefinita "non è mai stata rilasciata" e che i progetti ospitati continuavano a concedere i grant automaticamente, quindi la data potrebbe slittare: verifica cosa fa il tuo progetto. Senza un grant, la Data API restituisce 42501 |
| R6 | alta | RLS | grant ... on all tables in schema public / alter default privileges ... grant indiscriminati verso anon/authenticated (la rapida correzione per il 42501 che espone anche le tabelle senza RLS) |
| S1 | critica | Stripe | Webhook senza verifica della firma (constructEvent) |
| S2 | critica | Stripe | Il webhook analizza request.json() invece del corpo grezzo |
| S3 | media | Stripe | Il webhook non ha idempotenza su event.id |
| S4 | alta | Stripe | Prezzo o importo del checkout presi dalla richiesta |
| S5 | alta | Stripe | Accesso concesso nella pagina di successo del checkout invece che nel webhook |
| S6 | media | Stripe | Deduplica del webhook che può inghiottire un evento fallito: duplicati saltati senza stato pending/completed |
| S7 | bassa | Stripe | Periodo di fatturazione letto da items.data[0] (errato per gli abbonamenti multi-item dall'API 2025-03-31.basil) |
| H1 | media | Hardening | Nessun header di sicurezza in next.config |
| H2 | media | Hardening | dangerouslySetInnerHTML con un valore non letterale |
fixtures/vulnerable-app attiva tutti i 23 controlli basati su file, e i test verificano ciascuno nel file previsto. K3 viene testato su un repository git temporaneo.fixtures/clean-app (un'app di riferimento rafforzata) e fixtures/near-miss (codice sicuro che sembra contenere ciascun errore: webhook con corpo grezzo e idempotenza pending/completed, ricerca del periodo sicura per multi-item, redirect protetti, query admin filtrate per proprietario, select using (true), JSON-LD) devono produrre 0 risultati.npm test esegue la suite node:test, inclusi i flag della CLI e i codici di uscita. npm run smoke fornisce un riepilogo su una riga.