
Scanner de segurança estático local para aplicações Next.js, Supabase e Stripe: 24 verificações baseadas em AST para chaves expostas, RLS e grants ausentes, webhooks inseguros. CLI e GitHub Action.
Verificação de segurança local e gratuita para aplicações Next.js + Supabase + Stripe: chaves expostas, RLS e grants em falta, webhooks Stripe inseguros.
O teu agente de IA entregou a aplicação. Mas também entregou a tua chave secreta do Stripe, uma tabela sem RLS, ou um webhook que qualquer pessoa pode chamar? Um único comando descobre isso, localmente, em menos de um segundo.
npx github:edtrackai/nextjs-supabase-stripe-security-checker /path/to/your/app
Ainda não está no npm, então o npx o executa diretamente deste repositório do GitHub (requer Node 18+ e git).
- uses: edtrackai/nextjs-supabase-stripe-security-checker@v0
with:
fail-on: high
O fluxo de trabalho completo e as permissões estão abaixo e em docs/github-action.md.
Verificador de RLS do Supabase · Segurança de webhooks do Stripe · Verificação de segurança do Next.js · Concessões da Data API do 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 ou superior. Há uma dependência (@babel/parser). É gratuito e licenciado sob MIT, não requer conta, não faz chamadas de rede e nunca envia o seu código.
--fail-on=high termina com código 1, e --json fornece saída legível por máquina.Anúncio (pago, mesmo autor): Quer as correções? Launch Audit (12 dólares mais IVA onde aplicável) adiciona 28 verificações, um agente auditor de IA sem ferramentas Edit ou Write, e um plano de correção file:line.
| Flag | O que faz |
|---|---|
--json | Saída legível por máquina: {tool, version, root, filesScanned, counts, findings[]} |
--fail-on=<sev> | Termina com código 1 se algum resultado estiver em ou acima de critical / high / medium / low (none nunca falha). Termina com código 2 em argumentos inválidos. |
--list | Imprime o catálogo de verificações |
--quiet | Omite o rodapé de uma linha sobre as ferramentas pagas (impresso em stderr apenas num terminal; também desativado com NO_PROMO=1, CI ou GITHUB_ACTIONS) |
--help | Utilização |
Em CI: node path/to/bin/nss-security-check.js . --fail-on=high, ou use a GitHub Action (resumo da tarefa, anotações, um comentário fixo no PR, apenas GITHUB_TOKEN). Consulte o workflow de exemplo e as permissões em 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
As alterações estão listadas em CHANGELOG.md (a versão 0.5.0 adiciona a Action).
| ID | Severidade | Área | Verificação |
|---|---|---|---|
| K1 | crítica | Chaves | Chave secreta/restrita da Stripe ativa (sk_live_/rk_live_) no código-fonte, incluindo chaves divididas com + (a evidência é censurada) |
| K2 | crítica | Chaves | Variável NEXT_PUBLIC_ com aparência de segredo (service role, chave secreta, segredo de webhook…) |
| K3 | crítica | Chaves | Ficheiro .env com valores rastreados pelo git |
| K4 | crítica | Chaves | Segredo de servidor ou cliente admin do Supabase usado num componente "use client" |
| A1 | alta | Autenticação | auth.getSession() confiado no servidor em vez de getUser()/getClaims() |
| A2 | alta | Autenticação | Server Action escreve dados sem verificação de autenticação |
| A3 | alta | Autenticação | Rota de API (POST/PUT/PATCH/DELETE) escreve dados sem verificação de autenticação (rotas de webhook, cron e autenticação excluídas) |
| A4 | alta | Autenticação | Cliente admin consultado por um id fornecido no pedido sem filtro de proprietário (IDOR) |
| A5 | média | Autenticação | Redirecionamento aberto a partir de um parâmetro de consulta |
| R1 | crítica | RLS | Tabela criada sem row level security |
| R2 | crítica | RLS | Política de escrita com using (true) / with check (true) |
| R3 | alta | RLS | Política que permite à função anon escrever |
| R4 | alta | RLS | Função security definer sem search_path fixo |
| R5 | média | RLS | Tabela em public sem GRANT explícito. A Supabase anunciou que deixaria de aplicar grants por omissão em novas tabelas públicas a partir de 30 out 2026, mas no final de agosto um responsável da CLI da Supabase escreveu (supabase/cli PR #6337) que a alteração anterior por omissão "nunca chegou a ser implementada" e que os projetos alojados continuavam a aplicar grants automaticamente, pelo que a data pode mudar: verifica o que o teu próprio projeto faz. Sem um grant, a Data API devolve 42501 |
| R6 | alta | RLS | grant ... on all tables in schema public / alter default privileges ... grant indiscriminado para anon/authenticated (a correção rápida do 42501 que também expõe tabelas sem RLS) |
| S1 | crítica | Stripe | Webhook sem verificação de assinatura (constructEvent) |
| S2 | crítica | Stripe | Webhook analisa request.json() em vez do corpo em bruto |
| S3 | média | Stripe | Webhook sem idempotência sobre event.id |
| S4 | alta | Stripe | Preço ou montante do checkout obtido a partir do pedido |
| S5 | alta | Stripe | Acesso concedido na página de sucesso do checkout em vez de no webhook |
| S6 | média | Stripe | Deduplicação de webhook que pode engolir um evento falhado: duplicados ignorados sem estado pending/completed |
| S7 | baixa | Stripe | Período de faturação lido de items.data[0] (incorreto para subscrições com vários itens desde a API 2025-03-31.basil) |
| H1 | média | Hardening | Sem cabeçalhos de segurança em next.config |
| H2 | média | Hardening | dangerouslySetInnerHTML com um valor não literal |