Security Audit pre-gate — 2026-06-06 (media intensità)
Giro di sicurezza difensivo sul prodotto Multiverbe in vista del gate. Metodo: 4 agenti specializzati sul codice (secrets/integrità · AppSec API · isolamento multi-tenant · supply-chain/CI) + verifica diretta sul DB di produzione (
yqhixdqipojvgzfadufo) + ricerca web sul tooling di security testing 2026 (OWASP Multi-Tenant, RLS Supabase, pgTAP). Registro tecnico DB:Multiverbe/database/advisor-security-register.md.
Verdetto
Integrità intatta — nessun segno di compromissione. Working tree pulito, autori commit legittimi, nessun secret live, posture di base già solida (RLS su 105/105 tabelle, advisor sicurezza 0 WARN/ERROR, gateway PII fail-closed verso i provider US, SMTP cifrato in DB, gate CI completi: Semgrep ERROR+WARNING / gitleaks / TruffleHog / Trivy / typecheck+build / schema-drift). Unico elemento storico: un PAT Airtable committato tempo fa in file n8n ora cancellati, già revocato dal founder il 2026-06-01.
Da questa base abbiamo chiuso tutte le falle trovate e irrobustito l'autenticazione.
Tutto verificato a vivo (transazione in rollback: un utente autenticato non-membro vede 0
righe ovunque — CRM, bookings, messaggi, storage).
Falle chiuse
🔴 HIGH — fughe cross-tenant
- Storage (la più grave): il bucket privato
brain-documents(+ i pubblicisocial-media/workspace-logos/site-assets) avevano policy "loose" create a mano dalla dashboard Supabase (gated solo subucket_id, senza enforcement della cartella per-workspace). Conseguenza: un qualsiasi utente autenticato poteva leggere/cancellare i file riservati di OGNI altro tenant (i documenti del cervello/RAG). Migration2026-06-06_storage_workspace_folder_isolation.sqlapplicata in produzione + verificata live. Lezione permanente: niente policy storage dalla dashboard — solo via migration, sempre folder-scoped. - IDOR
sole-crm-suggestions: auth condizionale → senza header Authorization il controllo di appartenenza era saltato e l'endpoint (che gira inservice_role, scavalcando la RLS) restituiva i segnali CRM di qualsiasi workspace. Ora auth + membership obbligatori (GoTrue).
🟠 MEDIUM / 🟡 LOW
oauth/google-init: auth + membership obbligatori. ·web-hub/ingest: aggiunto il rate-limit che mancava. · CSP da Report-Only a enforcing (+ domini Sentry/PostHog). ·custom-domainGET: ownership check. · email transazionali: escape dei valori dinamici.
✅ M1 — robustezza auth (migrazione HMAC → GoTrue)
Tutto l'auth con JWT HMAC artigianale migrato al verificatore canonico GoTrue: booking (7 endpoint), site-builder (4), sector-deduction. 2 bug latenti scoperti e corretti:
- il verify HMAC a 2 parti non poteva validare il token Supabase a 3 parti che il frontend già manda → 401 latente (es. il bottone "no-show" non funzionava);
- il site-builder filtrava l'appartenenza su
team_members.user_email, una colonna inesistente → ownership doppiamente rotta. Ora usauser_id(pattern canonico).
Fortezza (anti-regressione)
Harness pgTAP di test cross-tenant (CRM + storage) + runbook + workflow CI opt-in
(Multiverbe/supabase/tests/). Quando una policy/migration tocca l'isolamento, il test
asserisce "tenant A non vede mai i dati di B".
Stato
- Già LIVE in prod: il fix storage (H2/M2/M3, migration applicata diretta).
- PR #312 (Multiverbe): tutto il resto. Bulk CI-verde (storage/H1/M4/M5/M6/L1/L2 +
rigenerazione types per un drift pre-esistente
ai_notifications); M1 verificato verde in locale (tsc · esm-guard · 714 test · lint) + Vercel (tsc && build). Al momento del push M1 la CI GitHub non aveva ancora rigirato (lag o cap minuti Actions — cf.project_ci_vercel_cost_2026_06_06).
🔴 Da fare / follow-up
- Merge PR #312 a CI-verde (o, se è il cap Actions, alzare il budget → poi merge).
- Eyeball CSP sul preview Vercel prima del merge (enforcing è l'unica modifica con rischio runtime): console senza violazioni, Stripe, cookie banner, Sentry/PostHog.
- Igiene (nessun buco attivo): time-box della CVE vitest dev-only · dedupe Dependabot/Renovate.
- Fortezza futura: CAPTCHA su auth (anti-bot) · baseline Supabase CLI per attivare il gate
pgTAP in CI · pentest esterno (Supabase lo consente sul nostro progetto; vieta
cross-tenant/DoS sull'infra condivisa) · rotazione
SMTP_ENCRYPTION_KEY.
Owner: Gregorio (decisioni) · Claude (esecuzione + onestà)