Il marketplace era operativo da otto mesi. Due co-fondatori, nessuno dei quali con un background in sicurezza, lo avevano costruito su Bubble.io con Stripe Connect per i pagamenti. Aveva elaborato oltre $40.000 in transazioni, contava 1.500 utenti registrati e stava crescendo costantemente grazie al passaparola.
Dodici minuti dopo l'inizio della scansione Penetrify, è emersa una scoperta Critica: la chiave API segreta di Stripe era incorporata in un file JavaScript lato client servito al browser di ogni visitatore. Era lì dal lancio. Quattro mesi di accesso completo in lettura/scrittura al loro intero account Stripe, disponibile a chiunque aprisse i DevTools.
Questa è la storia di come un'attività da $40.000 sia quasi diventata un monito.
La chiave API di Stripe che non dovresti mai esporre
Stripe rilascia due tipi di chiavi API: chiavi pubblicabili e chiavi segrete.
La chiave pubblicabile (pk_live_...) è progettata per essere utilizzata nel codice frontend. Può eseguire solo operazioni limitate — creare token di metodi di pagamento, confermare pagamenti — e non può accedere a dati sensibili dell'account. È sicuro esporla nel JavaScript lato client.
La chiave segreta (sk_live_...) è una questione completamente diversa. Con una chiave segreta di Stripe, puoi:
- Elencare tutti i clienti, i metodi di pagamento e gli abbonamenti
- Leggere le impronte digitali complete delle carte e gli indirizzi di fatturazione per tutti i clienti
- Emettere rimborsi arbitrari su qualsiasi transazione
- Creare addebiti su qualsiasi metodo di pagamento salvato
- Modificare o eliminare i programmi di pagamento e i dettagli del conto bancario
- Accedere a tutti gli account connessi (in questo caso, tutti gli account di pagamento dei venditori sul marketplace)
- Recuperare i dettagli del conto bancario per ogni venditore che si era registrato tramite Stripe Connect
La chiave segreta di Stripe è la chiave principale per l'intera infrastruttura di pagamento. Appartiene solo al codice lato server, in variabili d'ambiente che non vengono mai inviate al browser.
Come è finita nel bundle
Bubble.io è una piattaforma no-code che ti permette di costruire applicazioni web full-stack senza scrivere codice. Ha un sistema di workflow integrato per la logica lato server e un connettore API per servizi esterni. Per un team di due persone senza background ingegneristici, è un modo legittimo per lanciare rapidamente un prodotto reale.
La chiave segreta di Stripe è finita nel frontend per una ragione che sarà familiare a chiunque abbia costruito su una piattaforma no-code sotto pressione temporale: funzionava.
Durante lo sviluppo, il team aveva bisogno di effettuare chiamate API di Stripe dai workflow di Bubble. Hanno aggiunto la chiave segreta alla configurazione del connettore API. Ad un certo punto della configurazione — sia per un'incomprensione dell'esecuzione lato client vs. lato server, sia per un dettaglio di configurazione di Bubble non ovvio — la chiave è finita per essere inclusa nel payload JavaScript inviato al browser. I flussi di pagamento funzionavano. Le transazioni venivano elaborate correttamente. Non c'era nessun errore, nessun avviso, nessun sintomo evidente.
La piattaforma di Bubble gestisce correttamente gran parte dell'esecuzione lato server per impostazione predefinita, ma il confine tra ciò che viene eseguito nel browser e ciò che viene eseguito sui server di Bubble non è sempre visivamente ovvio nel builder no-code. Questo è un rischio ben documentato nella comunità di sviluppatori Bubble, ma è facile non notarlo quando ci si concentra sul far funzionare il prodotto piuttosto che sull'audit dei dati che la propria app invia al client.
Cosa significava realmente l'esposizione
Cerchiamo di essere specifici su cosa fosse a rischio durante quei quattro mesi.
Chiunque visitasse il marketplace poteva aprire i Chrome DevTools, navigare nella scheda Sources o Network, cercare nei file JavaScript per sk_live_ e trovare la chiave. Questo non richiede strumenti di hacking, nessuna conoscenza speciale e nessuna vulnerabilità al di là della capacità di fare clic destro e ispezionare una pagina web.
Con quella chiave, avrebbero potuto:
- Svuotare il saldo Stripe dell'attività emettendo rimborsi su transazioni completate, annullando ricavi già guadagnati
- Enumerare tutti i record dei clienti inclusi nomi, indirizzi email, dettagli parziali delle carte e indirizzi di fatturazione — una violazione di dati segnalabile ai sensi del GDPR e di varie leggi sulla privacy statali degli Stati Uniti
- Accedere ai dettagli del conto bancario dei venditori per ogni venditore che aveva collegato il proprio conto di pagamento tramite Stripe Connect — nomi, numeri di conto, numeri di routing
- Modificare i programmi di pagamento per reindirizzare i pagamenti dei venditori verso conti controllati dagli attaccanti
- Creare addebiti fraudolenti su qualsiasi metodo di pagamento del cliente salvato, fino ai limiti di Stripe per l'account
Ognuno di questi esiti avrebbe potuto porre fine all'attività. Insieme, rappresentano il tipo di violazione catastrofica che finisce nelle presentazioni delle conferenze sulla sicurezza.
La chiave Stripe era stata esposta per 4 mesi. Durante quel periodo, circa 8.000 persone avevano visitato il marketplace. Chiunque di loro avrebbe potuto trovarla.
Gli Altri Risultati
La chiave Stripe è stata la scoperta più grave, ma la scansione ha rivelato quattro problemi aggiuntivi:
MEDIUM — Regole di privacy di Bubble mal configurate
Le regole sulla privacy di Bubble controllano quali campi del database sono visibili a diversi ruoli utente. I record del profilo del venditore — che includevano i dettagli del conto bancario inseriti durante l'onboarding di Stripe Connect — erano visibili a qualsiasi utente autenticato tramite l'API di dati di Bubble. Anche senza la chiave Stripe, qualsiasi acquirente loggato avrebbe potuto interrogare le informazioni finanziarie del venditore.
MEDIUM — Enumerazione account tramite reset password
Il flusso di reset password restituiva risposte diverse per indirizzi email registrati rispetto a quelli non registrati. Una richiesta per un'email registrata restituiva "Controlla la tua casella di posta"; una richiesta per un'email non registrata restituiva "Nessun account trovato". Ciò consente a un attaccante di costruire un elenco di quali indirizzi email hanno account sulla piattaforma — utile per phishing mirato o credential stuffing.
MEDIUM — Nessuna Content Security Policy
L'applicazione non restituiva alcun header Content-Security-Policy. La funzionalità di ricerca rifletteva l'input fornito dall'utente senza codifica in alcuni contesti, rendendo possibile XSS riflesso. Senza una CSP, un payload XSS potrebbe esfiltrare token di sessione, effettuare chiamate API autenticate per conto della vittima o iniettare script malevoli nella pagina per altri visitatori.
LOW — Wildcard CORS
L'API restituiva Access-Control-Allow-Origin: *, consentendo a qualsiasi sito web di effettuare richieste cross-origin agli endpoint API e leggere le risposte. Per gli endpoint che restituiscono dati sensibili, ciò abilita l'esfiltrazione di dati cross-site da una pagina malevola visitata dalla vittima.
La Risposta: Immediata ed Efficace
I fondatori hanno agito entro un'ora dalla ricezione del rapporto.
Il primo passo è stato ruotare la chiave Stripe compromessa. Nella dashboard di Stripe, sotto Developers → API Keys, la chiave segreta live può essere "rollata" — generando una nuova chiave e invalidando immediatamente quella vecchia. Questo ha richiesto circa due minuti. Da quel momento, chiunque avesse estratto la chiave esposta non avrebbe più potuto usarla.
Il secondo passo è stato verificare i log degli eventi di Stripe per attività non autorizzate. La Dashboard di Stripe fornisce un log completo di ogni chiamata API effettuata con le tue chiavi, inclusi l'indirizzo IP e il timestamp di ogni richiesta. I fondatori hanno esaminato il log degli eventi per i quattro mesi precedenti cercando chiamate anomale — rimborsi che non avevano emesso, clienti che non avevano creato, modifiche ai pagamenti che non avevano effettuato. Non ne hanno trovate. La chiave era stata esposta ma — per quanto si potesse determinare — non era stata attivamente abusata.
Il terzo passo è stato correggere la configurazione di Bubble. Lavorando con uno sviluppatore Bubble che avevano assunto per alcune ore, hanno spostato tutte le chiamate API di Stripe nei workflow backend lato server di Bubble, dove le API keys non vengono trasmesse al browser. Anche le regole sulla privacy di Bubble sono state corrette per limitare i dati finanziari del venditore solo all'account venditore pertinente.
Come Trovare Questo nella Tua Applicazione
Se stai utilizzando un'applicazione Bubble, Webflow o qualsiasi altra applicazione no-code che si integra con Stripe, ecco come verificare se hai questo problema:
- Apri la tua applicazione in una finestra in incognito.
- Apri Chrome DevTools (F12) → scheda Network.
- Ricarica la pagina.
- Nella scheda Network, cerca i file JavaScript. Per ciascuno, cliccaci sopra e cerca (Ctrl+F)
sk_live_. - Controlla anche la scheda Sources. Usa Ctrl+Shift+F per cercare
sk_live_in tutti gli script caricati.
Se trovi la tua secret key di Stripe in uno di questi file, ruotala immediatamente prima di fare qualsiasi altra cosa, quindi indaga su come sia finita lì.
Questo stesso controllo si applica a qualsiasi altra API key sensibile: OpenAI, Twilio, SendGrid, AWS, Mailchimp. Qualsiasi key con accesso in scrittura o accesso a dati sensibili che trovi nel JavaScript lato client dovrebbe essere considerata compromessa e ruotata immediatamente.
Perché Questo Schema Persiste
L'esposizione delle secret key nei bundle frontend non è una nuova classe di vulnerabilità. È un rischio noto e ben documentato da quando le applicazioni web utilizzano API di terze parti. Allora perché continua ad accadere?
La risposta è che l'esperienza di sviluppo lo rende facile. Le piattaforme no-code e i moderni framework JavaScript sfumano il confine tra client e server in modi che non erano presenti nei precedenti modelli di sviluppo web. Le variabili d'ambiente con prefisso NEXT_PUBLIC_ vengono intenzionalmente inviate al browser; quelle senza prefisso no. Il contesto di esecuzione di Bubble dipende dal tipo di workflow che stai utilizzando. Le configurazioni dei bundle di Vite e webpack determinano cosa finisce nel browser.
Questi confini sono documentati ma non applicati a livello di tooling. Non c'è un errore in fase di build quando esponi accidentalmente una secret key. L'applicazione funziona correttamente. L'esposizione è silenziosa, indefinita e cresce ogni giorno che la key rimane valida.
L'unica difesa affidabile è scansionarla esplicitamente — e ruotarla rapidamente quando la trovi.
