[{"data":1,"prerenderedAt":810},["ShallowReactive",2],{"blog-pt-supabase-security-checker":3,"blog-index-pt":570},{"id":4,"title":5,"body":6,"category":522,"cover":523,"coverAlt":524,"description":525,"draft":526,"extension":527,"faq":528,"image":544,"keywords":545,"meta":558,"navigation":559,"ogTitle":560,"path":561,"published":562,"seo":563,"stem":564,"tldr":565,"updated":562,"__hash__":569},"blog_pt\u002Fblog\u002Fsupabase-security-checker.md","Supabase security checker: faça você mesmo as cinco verificações",{"type":7,"value":8,"toc":510},"minimark",[9,13,21,24,29,32,35,38,47,51,54,66,89,112,115,118,124,128,131,141,148,159,162,226,231,237,260,268,272,275,281,287,290,301,322,330,334,337,344,350,357,363,373,377,380,386,389,396,400,403,409,428,434,444,447,451,482,487,495,502],[10,11,12],"p",{},"Você pesquisou por um Supabase security checker e apareceram nove. Um quer o seu\nrepositório. Outro quer uma extensão de navegador. Outro quer acesso de leitura\nà sua conta inteira do Supabase, o que é parecido o bastante com aquilo que\nestava te preocupando para te fazer hesitar.",[10,14,15,16,20],{},"Aqui está o que nenhuma dessas páginas de produto diz em voz alta. ",[17,18,19],"strong",{},"São cinco\nverificações, e você pode fazer todas sozinho",", sem conta, sem instalar nada e\nsem nenhuma das credenciais que seria perigoso entregar. Dez minutos num\nterminal cobrem o mesmo terreno que as ferramentas.",[10,22,23],{},"As cinco abaixo são as que o nosso próprio scanner roda contra um projeto\nSupabase, escritas como comandos. Se você construiu com Lovable, Bolt, v0,\nCursor, Replit, Windsurf ou Base44 e o seu app guarda qualquer coisa, o banco\npor trás é muito provavelmente Supabase, e estas são as perguntas que um\nestranho faria a ele.",[25,26,28],"h2",{"id":27},"o-que-um-supabase-security-checker-verifica-de-verdade","O que um Supabase security checker verifica de verdade?",[10,30,31],{},"O seu app publicado. Os ajustes dentro do projeto são trabalho de outra\nferramenta, e o Supabase já entrega essa ferramenta.",[10,33,34],{},"O Security Advisor no seu painel lê o catálogo do próprio projeto: quais tabelas\nestão com Row Level Security desligada, quais funções têm um search path frouxo,\nquais extensões vivem no schema public. Ele está lendo o que você configurou.",[10,36,37],{},"Um checker lê o que o seu app entrega a um estranho. O bundle JavaScript que\nseus visitantes baixam, a resposta que uma tabela dá a uma requisição sem login,\no conteúdo de um bucket de armazenamento, os cabeçalhos das suas páginas. Da sua\nconfiguração ele não vê nada, e não precisa, porque está olhando a consequência\ndela.",[10,39,40,41,46],{},"As duas metades se separam com mais frequência do que os nomes sugerem. Uma\ntabela pode passar pelo Advisor com a chave ligada e uma policy escrita, e ainda\nassim entregar as linhas dela para qualquer pessoa, porque a policy que foi\nescrita deixa todo mundo entrar. Isso merece uma leitura própria se for novidade\npara você:\n",[42,43,45],"a",{"href":44},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","o botão não é a proteção",".",[25,48,50],{"id":49},"verificação-1-qual-chave-do-supabase-o-seu-app-entrega","Verificação 1: qual chave do Supabase o seu app entrega?",[10,52,53],{},"Abra o seu app no navegador, aperte F12 e olhe uma única requisição.",[10,55,56,57,61,62,65],{},"Vá para a aba Rede, recarregue a página e digite ",[58,59,60],"code",{},"supabase"," no filtro. Seu app\nvai fazer pelo menos uma requisição para um endereço terminado em\n",[58,63,64],{},".supabase.co",". Clique nela. As duas coisas de que você precisa para o resto do\nartigo estão ali dentro:",[67,68,69,80],"ul",{},[70,71,72,75,76,79],"li",{},[17,73,74],{},"O endereço da requisição"," começa com a URL do seu projeto, algo como\n",[58,77,78],{},"https:\u002F\u002Fabcdefghij.supabase.co",". As verificações 2 e 3 miram nele.",[70,81,82,88],{},[17,83,84,85],{},"O cabeçalho de requisição ",[58,86,87],{},"apikey"," carrega a chave que o seu app entrega a\ncada visitante.",[10,90,91,92,95,96,99,100,103,104,107,108,46],{},"Copie as duas para algum lugar e então leia a própria chave. Uma que começa com\n",[58,93,94],{},"sb_publishable_"," pertence ao seu app e não há nada a consertar. Uma que começa\ncom ",[58,97,98],{},"sb_secret_"," nunca pertence, e encontrá-la encerra a lista mais cedo: gire\nessa chave hoje, antes de tudo o mais nesta página. Projetos mais antigos\ncarregam um par sem prefixo legível, ",[58,101,102],{},"anon"," e ",[58,105,106],{},"service_role",", e distinguir os\ndois significa\n",[42,109,111],{"href":110},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","ler a role dentro da chave",[10,113,114],{},"Esse último caso é raro. Entre os 30.998 apps no ar que escaneamos em agosto de\n2026, uma chave secreta do Supabase no navegador apareceu três vezes.",[10,116,117],{},"Enquanto a aba Rede estiver aberta, anote os nomes de tabela que você conseguir\nver nesses endereços. A próxima verificação precisa deles.",[119,120],"diagram",{"alt":121,"caption":122,"src":123},"Um painel de bundle no centro contendo uma chave e um endereço. Uma seta sai para a esquerda até uma janela de navegador, marcada com os números 4 e 5. Outra sai para a direita até um banco de dados e um bucket de armazenamento rotulado .supabase.co, marcada com 2 e 3.","Tudo o que vem a seguir mira em um de dois endereços: o do seu app e o do seu projeto. A verificação 1 é o que te dá o segundo.","\u002Fblog\u002Fsupabase-security-checker\u002Ftwo-addresses-1600x680.png",[25,125,127],{"id":126},"verificação-2-suas-tabelas-respondem-a-um-estranho","Verificação 2: suas tabelas respondem a um estranho?",[10,129,130],{},"Pergunte ao banco quantas linhas ele entregaria a alguém sem login, e leia o\nnúmero na resposta.",[132,133,139],"pre",{"className":134,"code":136,"language":137,"meta":138},[135],"language-bash","curl -s -i \\\n  -H \"apikey: SUA_CHAVE_PUBLICAVEL\" \\\n  -H \"Prefer: count=exact\" \\\n  -H \"Range: 0-0\" \\\n  \"https:\u002F\u002FSEU_PROJETO.supabase.co\u002Frest\u002Fv1\u002Fprofiles?select=count\" \\\n  | grep -i content-range\n","bash","",[58,140,136],{"__ignoreMap":138},[10,142,143,144,147],{},"Ponha a chave e o endereço do projeto da verificação 1, e o nome da sua própria\ntabela onde está ",[58,145,146],{},"profiles",". O curl já vem instalado no macOS, no Linux e no\nWindows atual, então não há nada para baixar antes.",[10,149,150,151,154,155,158],{},"Essa requisição não busca linha nenhuma. ",[58,152,153],{},"select=count"," pede uma contagem,\n",[58,156,157],{},"Range: 0-0"," não pede nenhuma das linhas em si, e a resposta inteira chega em um\núnico cabeçalho. É a mesma requisição que o nosso scanner faz, e é por isso que\nele pode rodar contra o app no ar de alguém sem tocar nos dados dessa pessoa.",[10,160,161],{},"Quatro coisas podem voltar, e uma delas é um achado:",[163,164,165,178],"table",{},[166,167,168],"thead",{},[169,170,171,175],"tr",{},[172,173,174],"th",{},"O que aparece",[172,176,177],{},"O que significa",[179,180,181,192,202,216],"tbody",{},[169,182,183,189],{},[184,185,186],"td",{},[58,187,188],{},"content-range: *\u002F0",[184,190,191],{},"Nada legível sem login. Essa tabela está fazendo o trabalho dela.",[169,193,194,199],{},[184,195,196],{},[58,197,198],{},"content-range: 0-0\u002F128",[184,200,201],{},"128 linhas ao alcance de qualquer um com a chave que viaja na sua página.",[169,203,204,213],{},[184,205,206,209,210],{},[58,207,208],{},"401"," ou ",[58,211,212],{},"403",[184,214,215],{},"A chave foi recusada antes de chegar à tabela. Sem resposta, não limpo.",[169,217,218,223],{},[184,219,220],{},[58,221,222],{},"404",[184,224,225],{},"Não existe tabela com esse nome. Ou você chutou, ou ela se escreve de outro jeito.",[119,227],{"alt":228,"caption":229,"src":230},"Dois painéis de resposta lado a lado. Os dois mostram a mesma linha de status 200. O da esquerda enquadra um cabeçalho content-range terminado em barra e zero, e recebe um visto verde; o da direita enquadra o mesmo cabeçalho terminado em 128, e recebe um xis vermelho.","As duas requisições deram certo. Um cabeçalho é toda a diferença entre uma tabela que faz o trabalho dela e uma que entrega linhas a quem pedir.","\u002Fblog\u002Fsupabase-security-checker\u002Fthe-one-header-1600x700.png",[10,232,233,234,236],{},"A recusa é a linha com a qual é preciso ter cuidado. Um ",[58,235,208],{}," diz que a\nrequisição parou antes de chegar à tabela, o que não te conta nada sobre a\ntabela estar protegida, e é a mais fácil das quatro de arredondar para um visto\nverde.",[10,238,239,240,243,244,243,246,249,250,243,253,243,256,259],{},"Rode o comando para cada tabela que o seu app nomeou na verificação 1, e depois\npara as comuns que um app costuma ter: ",[58,241,242],{},"users",", ",[58,245,146],{},[58,247,248],{},"customers",",\n",[58,251,252],{},"orders",[58,254,255],{},"messages",[58,257,258],{},"invoices",". Nessas seis moram os dados de outras pessoas.",[10,261,262,263,267],{},"Essa é a verificação que mais encontra. Dos 3.680 apps com Supabase em que\nconseguimos completá-la, 2.096 tinham pelo menos uma tabela respondendo a uma\nrequisição sem login, e em 394 deles a tabela aberta tinha nome de pessoas. A\n",[42,264,266],{"href":265},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","medição completa e de que ela é uma fatia","\nestá em um artigo separado.",[25,269,271],{"id":270},"verificação-3-um-bucket-de-armazenamento-lista-os-próprios-arquivos","Verificação 3: um bucket de armazenamento lista os próprios arquivos?",[10,273,274],{},"Peça a um bucket o conteúdo dele e veja se volta alguma coisa.",[132,276,279],{"className":277,"code":278,"language":137,"meta":138},[135],"curl -s -X POST \\\n  -H \"apikey: SUA_CHAVE_PUBLICAVEL\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"prefix\":\"\",\"limit\":1}' \\\n  \"https:\u002F\u002FSEU_PROJETO.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Flist\u002Favatars\"\n",[58,280,278],{"__ignoreMap":138},[10,282,283,286],{},[17,284,285],{},"Mande o body."," Um POST para esse endereço sem nada dentro volta com \"Body\ncannot be empty\" para todo bucket de todo projeto, esteja ele configurado como\nestiver. Sabemos disso porque a nossa própria verificação de buckets saiu assim\ne passou meses informando alegremente que nada era listável.",[10,288,289],{},"Duas formas de resposta:",[67,291,292,298],{},[70,293,294,297],{},[58,295,296],{},"[]"," quer dizer que o bucket está fechado, ou que não existe bucket com esse\nnome. De fora você não consegue saber qual das duas, então uma lista vazia não\né prova de nada.",[70,299,300],{},"Um array com um arquivo dentro quer dizer que um estranho pode pedir ao seu\nprojeto um diretório daquele bucket e recebê-lo.",[10,302,303,304,243,307,243,310,243,313,243,316,243,319,46],{},"Experimente os nomes de bucket que o seu app usou, e depois os comuns:\n",[58,305,306],{},"avatars",[58,308,309],{},"public",[58,311,312],{},"uploads",[58,314,315],{},"files",[58,317,318],{},"images",[58,320,321],{},"documents",[10,323,324,325,329],{},"Listável e público são dois ajustes diferentes guardados em dois lugares\ndiferentes, e\n",[42,326,328],{"href":327},"\u002Fblog\u002Fsupabase-storage-bucket-public","a diferença decide o quanto um bucket público importa",".\nA listagem é a que se fecha, porque ela poupa de um estranho o trabalho de\nadivinhar um nome de arquivo. Dos 27.269 apps em que pudemos perguntar, 792\nresponderam com uma lista.",[25,331,333],{"id":332},"verificação-4-seu-código-fonte-é-publicado-junto-com-o-app","Verificação 4: seu código-fonte é publicado junto com o app?",[10,335,336],{},"Leia a última linha do seu bundle JavaScript.",[10,338,339,340,343],{},"De volta à aba Rede da verificação 1, ache o maior arquivo ",[58,341,342],{},".js"," que o seu app\ncarregou e copie o endereço dele. Então:",[132,345,348],{"className":346,"code":347,"language":137,"meta":138},[135],"curl -s \"https:\u002F\u002Fseu-app.example\u002Fassets\u002Findex-abc123.js\" | tail -c 120\n",[58,349,347],{"__ignoreMap":138},[10,351,352,353,356],{},"Uma última linha dizendo ",[58,354,355],{},"\u002F\u002F# sourceMappingURL=index-abc123.js.map"," quer dizer\nque o seu build escreveu um source map e disse aos navegadores onde ele está. Se\nele de fato publicou o arquivo, isso uma requisição a mais esclarece:",[132,358,361],{"className":359,"code":360,"language":137,"meta":138},[135],"curl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\\n\" \\\n  \"https:\u002F\u002Fseu-app.example\u002Fassets\u002Findex-abc123.js.map\"\n",[58,362,360],{"__ignoreMap":138},[10,364,365,368,369,46],{},[58,366,367],{},"200"," quer dizer que qualquer um pode baixar. Um source map transforma o\nJavaScript comprimido de volta nos seus arquivos originais, com a sua estrutura\nde pastas, seus comentários e sua lógica intactos. O que ele expõe é o seu\ncódigo, e qualquer chave que ele revele já estava ali do lado no bundle, que era\no assunto da verificação 1. 3.885 dos 30.987 apps que pudemos examinar publicam\no deles, e em alguns builders isso é um padrão da plataforma e não uma decisão\nde alguém:\n",[42,370,372],{"href":371},"\u002Fblog\u002Fsource-maps-exposed-in-production","o que um source map publicado mostra",[25,374,376],{"id":375},"verificação-5-o-que-a-sua-hospedagem-envia-com-cada-página","Verificação 5: o que a sua hospedagem envia com cada página",[10,378,379],{},"Uma requisição ao endereço do próprio app, lendo o que voltou junto.",[132,381,384],{"className":382,"code":383,"language":137,"meta":138},[135],"curl -s -i \"https:\u002F\u002Fseu-app.example\" | grep -i -E \\\n  \"content-security-policy|strict-transport-security|x-frame-options|x-content-type-options|referrer-policy\"\n",[58,385,383],{"__ignoreMap":138},[10,387,388],{},"Cinco cabeçalhos, e os que não aparecem são os que estão faltando. Eles mandam o\nnavegador recusar a página se ela for carregada dentro do site de outra pessoa,\ninsistir numa conexão criptografada na próxima vez, e parar de adivinhar que\ntipo de arquivo acabou de receber.",[10,390,391,392,46],{},"Quase todo app falha nessa e quase ninguém consegue agir a respeito. A 30.756\ndos 30.981 apps que pudemos examinar faltava pelo menos um, porque quem envia\nesses cabeçalhos é a plataforma de hospedagem e um dono em subdomínio de builder\nnão tem onde mudá-los. Nós contamos e limitamos a médio:\n",[42,393,395],{"href":394},"\u002Fblog\u002Fmissing-security-headers","o que cabeçalhos faltando preveem e o que não preveem",[25,397,399],{"id":398},"como-ler-o-que-você-encontrou","Como ler o que você encontrou",[10,401,402],{},"Por gravidade, que não é a ordem em que você as rodou.",[10,404,405,408],{},[17,406,407],{},"Uma chave secreta no bundle vem primeiro."," Ela pula todas as regras que você\nescreveu em todas as tabelas, então gire essa chave antes de olhar qualquer\noutra coisa aqui.",[10,410,411,414,415,243,417,243,419,103,421,423,424,427],{},[17,412,413],{},"Uma tabela cheia de pessoas respondendo à verificação 2 vem em seguida."," Em\n",[58,416,242],{},[58,418,146],{},[58,420,252],{},[58,422,255],{}," moram os dados de outra gente, e eles\nestão alcançáveis agora. Uma tabela ",[58,425,426],{},"products"," respondendo do mesmo jeito pode\nestar exatamente certa, e você é a única pessoa capaz de distinguir as duas.",[10,429,430,433],{},[17,431,432],{},"Depois um bucket listável, depois os maps e os cabeçalhos",", que costumam ser\nos padrões da sua plataforma e não algo que você escolheu.",[10,435,436,437,440,441,443],{},"Uma coisa para levar das cinco. ",[17,438,439],{},"Uma verificação que não obteve resposta não\npassou."," Um ",[58,442,208],{},", uma requisição que estourou o tempo, uma tabela cujo nome\nvocê chutou errado: cada uma delas é uma pergunta ainda em aberto. Nosso scanner\nescreve \"Não foi possível verificar\" nessas linhas e deixa a nota em paz, e\nfazer isso à mão significa manter essa lista você mesmo.",[10,445,446],{},"Tudo isso descreve também o app que estava no ar no momento em que você\nperguntou. A Row Level Security é desligada para uma página carregar, um bucket\né aberto para um upload, uma chave é colada para um recurso sair hoje à noite.",[25,448,450],{"id":449},"o-que-fazer-esta-semana","O que fazer esta semana",[452,453,454],"key-takeaways",{},[67,455,456,470,473,476,479],{},[70,457,458,459,243,461,243,463,243,465,103,467,469],{},"Rode a verificação 2 contra cada tabela que o seu app nomeia, e depois contra ",[58,460,242],{},[58,462,146],{},[58,464,248],{},[58,466,252],{},[58,468,255],{},". É ali que estão os achados.",[70,471,472],{},"Se a verificação 1 revelou uma chave secreta, gire essa chave primeiro. Apagar do código deixa o valor antigo funcionando para quem já o tem.",[70,474,475],{},"Anote toda sonda que recebeu recusa ou resposta nenhuma. Essas ficam sem resposta, e uma pergunta sem resposta não é um resultado limpo.",[70,477,478],{},"Deixe em paz as tabelas que devem ser públicas. Uma lista de produtos respondendo a um estranho é o seu app funcionando direito.",[70,480,481],{},"Rode as cinco de novo depois de um deploy e depois que alguém mexer numa regra do banco. Nenhum dos dois se anuncia sozinho.",[119,483],{"alt":484,"caption":485,"src":486},"Um relatório da Reeve. Um bloco âmbar grande com a letra C, o número 85 de 100 embaixo, e nove linhas à direita, cada uma com um ícone de verificação e uma barra. Sete linhas trazem um visto verde, a linha do armazenamento traz um xis vermelho, e a linha do banco de dados traz um espaço tracejado vazio no lugar da marca.","As mesmas cinco verificações, mais outras quatro, devolvidas como relatório. A pontuação é 85 e a nota é C, porque um achado alto limita a letra diga o que disser a aritmética. A linha tracejada é o banco de dados, que nunca respondeu.","\u002Fblog\u002Fsupabase-security-checker\u002Fgrade-score-and-checks-1600x760.png",[10,488,489,490,494],{},"Nosso ",[42,491,493],{"href":492},"\u002Fsecurity-scanner","scanner de segurança gratuito"," roda essas cinco e mais\nquatro contra qualquer URL no ar em uns vinte segundos, sem conta e sem que você\nentregue credenciais. Ele lê, nunca escreve, e onde não consegue resposta ele\ndiz isso na linha.",[10,496,497,498,46],{},"As cinco você pode fazer sozinho hoje. O que nenhuma passada isolada consegue te\ndizer é se as respostas continuam as mesmas no mês que vem, e foi para isso que\nconstruímos o Reeve Care: ele repete essas verificações em uma agenda, te manda\ne-mail quando uma resposta piora, e guarda backups verificados do seu banco\nSupabase, mais os arquivos que seus usuários enviam assim que você conecta uma\ncredencial de armazenamento.\n",[42,499,501],{"href":500},"\u002F#pricing","O que ele vigia e quanto custa",[10,503,504,505,509],{},"Se um terminal não é onde você quer estar, o passo a passo em linguagem simples\npara ",[42,506,508],{"href":507},"\u002Fis-your-supabase-app-safe","apps com Supabase"," explica para que serve cada\num desses ajustes e onde encontrá-lo no painel.",{"title":138,"searchDepth":511,"depth":511,"links":512},3,[513,515,516,517,518,519,520,521],{"id":27,"depth":514,"text":28},2,{"id":49,"depth":514,"text":50},{"id":126,"depth":514,"text":127},{"id":270,"depth":514,"text":271},{"id":332,"depth":514,"text":333},{"id":375,"depth":514,"text":376},{"id":398,"depth":514,"text":399},{"id":449,"depth":514,"text":450},"Noções de segurança","\u002Fblog\u002Fsupabase-security-checker\u002Fcover-1200x630.png","Uma janela de terminal vista de frente, com cinco comandos curtos digitados sob um prompt verde e um cursor esperando na sexta linha.","Um Supabase security checker lê o seu app publicado em vez das configurações do projeto. Aqui estão as cinco verificações e como fazer cada uma sozinho.",false,"md",[529,532,535,538,541],{"q":530,"a":531},"O Security Advisor do Supabase pega tudo?","Pega tudo na metade dele. O Advisor lê a configuração do seu projeto e informa tabelas com Row Level Security desligada, funções com search path frouxo e ajustes parecidos que você controla pelo painel. O que ele não consegue ver é o seu app publicado: qual chave foi parar no JavaScript que seus visitantes baixam, se uma policy que você escreveu de fato barra uma requisição anônima, ou quais cabeçalhos a sua hospedagem envia. Rode o Advisor e as cinco verificações deste artigo, porque eles olham para coisas diferentes.",{"q":533,"a":534},"É seguro rodar essas verificações contra o meu próprio projeto?","Sim. Todo comando aqui lê e nenhum escreve. A verificação de tabelas pede ao seu banco uma contagem de linhas e lê o número de um cabeçalho da resposta, então nenhuma linha é buscada. A de buckets pede uma listagem e para por aí, sem baixar arquivo nenhum. As duas últimas são uma requisição de página comum, do tipo que seus visitantes fazem o dia inteiro. Rodá-las contra um projeto que não é seu é outra questão, e a resposta é pedir permissão a quem é dono antes.",{"q":536,"a":537},"Minha chave anon está no meu bundle. Isso é um problema?","Não. A chave anon nos projetos antigos, e sb_publishable_ nos novos, foi feita para ficar no código que seus visitantes baixam. Ela nomeia o seu projeto e sozinha não concede nada; é a Row Level Security que decide quais linhas uma requisição recebe de volta. A chave que nunca pode estar ali é a secreta, chamada service_role nos projetos antigos e sb_secret_ nos novos, porque ela pula todas as regras que você escreveu.",{"q":539,"a":540},"O que significa content-range: *\u002F0?","É o seu banco dizendo que vai entregar zero linhas daquela tabela para quem está chamando. O asterisco quer dizer que a resposta não contém linha alguma, e o número depois da barra é a contagem que quem chamou tem permissão de ver. Então *\u002F0 é a resposta que você quer de uma tabela com dados pessoais, e 0-0\u002F128 quer dizer que 128 linhas estão ao alcance de qualquer um que tenha a chave que viaja no seu app.",{"q":542,"a":543},"Preciso da minha chave service_role para testar isso?","Não, e um checker que pede essa chave está pedindo a coisa errada. Toda verificação aqui usa a chave publicável que já está no seu app, porque é essa que um estranho teria. Testar com uma chave secreta diz o que um administrador alcança, o que nunca esteve em dúvida. Não cole uma chave service_role nem sb_secret_ em nenhum scanner, incluindo o nosso: nada do que fazemos precisa dela.","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",[546,547,548,549,550,551,552,553,554,555,556,557],"supabase security checker","verificar segurança supabase","supabase rls checker","scanner de segurança supabase","auditoria de segurança supabase","testar row level security supabase","supabase security advisor","tabelas expostas supabase","meu banco supabase é público","chave anon supabase exposta","verificar bucket público supabase","scanner de vazamento supabase",{},true,"Supabase security checker: as cinco verificações","\u002Fblog\u002Fsupabase-security-checker","2026-09-06",{"title":5,"description":525},"blog\u002Fsupabase-security-checker",[566,567,568],"Um Supabase security checker lê o seu app no ar do jeito que um estranho lê: o bundle que ele entrega, as respostas das suas tabelas, seus buckets de armazenamento, seus cabeçalhos.","O Security Advisor do próprio Supabase lê a outra metade, que é a configuração do seu projeto. Nenhum dos dois enxerga o que o outro enxerga.","Cinco verificações cobrem a vista de fora. Todas rodam de um terminal, não pedem conta nenhuma e juntas levam uns dez minutos.","Ys6h0TyLu2s5XcBQBq5SUQoXVDSAxPZsC9mCSY_6H7M",[571,578,584,590,596,602,608,614,620,626,632,638,644,650,656,662,668,674,675,681,686,692,698,704,710,716,722,728,734,740,746,752,757,763,769,774,778,784,790,795,800,806],{"path":572,"title":573,"description":574,"published":575,"category":576,"image":577,"draft":526},"\u002Fblog\u002Fsupabase-backup-auth-users","Por que seu dump do Supabase não tem usuários dentro","Rode supabase db dump sozinho e você recebe a forma do seu banco e nenhuma das linhas dele, sem o schema auth onde seus usuários moram.","2026-09-23","Backups","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":579,"title":580,"description":581,"published":582,"category":522,"image":583,"draft":526},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domínio expirado, site fora do ar: o que acontece agora","Seu domínio expirou e seu site está fora do ar. O relógio que começa a correr, por que o certificado é o problema menor, e como conferir os dois.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":585,"title":586,"description":587,"published":588,"category":522,"image":589,"draft":526},"\u002Fblog\u002Fis-lovable-safe","O Lovable é seguro? O que vimos em 18.554 aplicativos Lovable","O Lovable é seguro? Passamos 18.554 aplicativos Lovable no ar por nove verificações. A plataforma foi a mais limpa de cinco. Os achados estavam nos aplicativos.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":591,"title":592,"description":593,"published":594,"category":522,"image":595,"draft":526},"\u002Fblog\u002Fvibe-coded-app-security-checklist","O checklist de segurança do vibe coding, em nove verificações","Um checklist de segurança do vibe coding com nove itens, cada um verificável no seu app de fora por qualquer pessoa, e cada um com um teste de uma linha.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":597,"title":598,"description":599,"published":600,"category":522,"image":601,"draft":526},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Uma chave secreta da Stripe no frontend pode mover dinheiro","Uma chave secreta da Stripe exposta no seu frontend pode reembolsar, cobrar e ler cada ficha de cliente que você tem. Sua chave pk_live_ é que deve estar aí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":603,"title":604,"description":605,"published":606,"category":522,"image":607,"draft":526},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variáveis de ambiente do Vite expostas: o prefixo diz publique isto","Variáveis de ambiente do Vite expostas no seu app: fizeram o que o prefixo pediu. VITE_ e NEXT_PUBLIC_ significam publique isto, e a IA nunca soube o custo.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":609,"title":610,"description":611,"published":612,"category":522,"image":613,"draft":526},"\u002Fblog\u002Fbase44-source-maps","Segurança no Base44: o que um scan aponta e o que é seu para corrigir","Segurança no Base44 em 5.438 apps escaneados: três achados em quase todos são da plataforma, o source map é o selo do Base44, e a sua parte é uma lista curta.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":615,"title":616,"description":617,"published":618,"category":522,"image":619,"draft":526},"\u002Fblog\u002Fis-cursor-ai-safe","O Cursor AI é seguro? O editor, o código e o app que você publicou","O Cursor AI é seguro? Três perguntas em uma busca: o que o Cursor guarda, o que o código que ele escreve erra, e se o app que você publicou está aberto.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":621,"title":622,"description":623,"published":624,"category":522,"image":625,"draft":526},"\u002Fblog\u002Fis-replit-safe","O Replit é seguro? O que vimos em 3.042 aplicativos Replit no ar","O Replit é seguro? Passamos 3.042 aplicativos Replit no ar por nove verificações externas. Os achados estavam no aplicativo publicado, não no host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":627,"title":628,"description":629,"published":630,"category":576,"image":631,"draft":526},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: sua cópia do banco não tem nenhum arquivo","Um Supabase storage backup é uma tarefa à parte. Os backups do banco guardam a lista dos seus arquivos e nenhum deles, então cada upload fica quebrado.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":633,"title":634,"description":635,"published":636,"category":576,"image":637,"draft":526},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery do Supabase: preço e limites","O point-in-time recovery do Supabase rebobina seu banco para qualquer segundo da última semana. Custa $100 por mês além do Pro e cobre só o banco.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":639,"title":640,"description":641,"published":642,"category":576,"image":643,"draft":526},"\u002Fblog\u002Fsupabase-project-paused-recover","Projeto Supabase pausado? Seus dados continuam lá","O Supabase pausou seu projeto depois de uma semana sem atividade. Nada foi apagado, Restaurar fica ao lado do nome e você tem um ano antes disso mudar.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":645,"title":646,"description":647,"published":648,"category":522,"image":649,"draft":526},"\u002Fblog\u002Fsafest-ai-app-builder","Qual builder de apps com IA é mais seguro? 30.998 apps testados","Qual builder de apps com IA é mais seguro? Escaneamos 30.998 apps no ar do Lovable, Base44, Replit, v0 e Bolt. O builder não é o que decide sua nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":651,"title":652,"description":653,"published":654,"category":522,"image":655,"draft":526},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Ative Row Level Security em toda tabela do Supabase e comprove","Ativar Row Level Security no Supabase sem política fecha a tabela por completo. Uma política sem a chave ligada não faz nada. Aqui está o SQL, e o teste.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":657,"title":658,"description":659,"published":660,"category":522,"image":661,"draft":526},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": o que o aviso não vê","O Supabase marca \"RLS disabled in public\" como erro. Ele não diz nada sobre a política de leitura que deixa a sua tabela igualmente aberta.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":663,"title":664,"description":665,"published":666,"category":522,"image":667,"draft":526},"\u002Fblog\u002Frotate-supabase-service-role-key","Como rotacionar uma chave service_role do Supabase vazada","O Supabase manda fechar o vazamento primeiro. Outros guias mandam rotacionar agora. O que vale depende de para onde a sua chave service_role vazou.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":669,"title":670,"description":671,"published":672,"category":522,"image":673,"draft":526},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Scanners de segurança para vibe coding comparados, o nosso incluído","O melhor scanner de segurança para vibe coding depende de três perguntas que nenhuma lista de recursos responde. Dez ferramentas comparadas, com preços.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":561,"title":5,"description":525,"published":562,"category":522,"image":544,"draft":526},{"path":676,"title":677,"description":678,"published":679,"category":522,"image":680,"draft":526},"\u002Fblog\u002Fvibe-coding-security-scanner","Scanner de segurança para vibe coding: o que ele não vê","Um scanner de segurança para vibe coding lê seu app no ar, de fora. O que isso cobre, as quatro coisas que ele não consegue ver e como ler o resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":394,"title":682,"description":683,"published":684,"category":522,"image":685,"draft":526},"Cabeçalhos de segurança faltando: quando isso importa","Cabeçalhos de segurança faltando é o achado que nosso scanner mais imprime. Contra o que eles protegem e quando são a linha menos urgente do relatório.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":687,"title":688,"description":689,"published":690,"category":522,"image":691,"draft":526},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Sua chave de API da OpenAI está exposta no frontend. Troque-a.","Uma chave de API da OpenAI exposta no frontend não pode ser presa a um domínio. Troque-a hoje, mova a chamada para o seu servidor e limite o gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":693,"title":694,"description":695,"published":696,"category":522,"image":697,"draft":526},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Chave de API exposta no frontend: o que 30.998 apps entregam","Uma chave de API exposta no seu frontend costuma ser uma chave do Google Maps. Escaneamos 30.998 apps vibe-coded e contamos quais segredos vazam de verdade.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":699,"title":700,"description":701,"published":702,"category":576,"image":703,"draft":526},"\u002Fblog\u002Fsupabase-backup-tools-compared","Ferramentas de backup do Supabase comparadas, a nossa incluída","Quatro tipos de ferramenta de backup do Supabase, o que cada uma copia de verdade e quando uma GitHub Action gratuita ganha de pagar, nós inclusive.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":705,"title":706,"description":707,"published":708,"category":522,"image":709,"draft":526},"\u002Fblog\u002Freplit-secrets-explained","Como usar secrets no Replit, e o que ainda assim é publicado","Como usar secrets no Replit: adicionar um, ler de volta e resolver as duas causas do undefined. E as chaves que a ferramenta Secrets não consegue proteger.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":711,"title":712,"description":713,"published":714,"category":576,"image":715,"draft":526},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups do plano gratuito do Supabase: como fazer sem terminal","No plano gratuito do Supabase não existe backup nenhum: a cópia é você que faz. Como fazer uma pelo painel e o que a rota do CSV deixa para trás.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":717,"title":718,"description":719,"published":720,"category":522,"image":721,"draft":526},"\u002Fblog\u002Fis-supabase-secure","O Supabase é seguro? É. Seu projeto é outra pergunta","O Supabase é seguro? A plataforma é auditada, criptografada e passa por pentests. A documentação deles diz onde isso termina e começam suas configurações.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":723,"title":724,"description":725,"published":726,"category":522,"image":727,"draft":526},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Onde ficam as chaves de API do Supabase: anon, service_role e URL","A URL do projeto, a chave anon e a chave service_role ficam todas numa página do painel. Aqui está onde ela fica, e qual dos quatro valores vai no seu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":729,"title":730,"description":731,"published":732,"category":522,"image":733,"draft":526},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy no Supabase. E agora?","\"New row violates row-level security policy\" significa que o Supabase recusou uma escrita. O conserto rápido reabre a tabela para qualquer um.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":735,"title":736,"description":737,"published":738,"category":522,"image":739,"draft":526},"\u002Fblog\u002Fcors-wildcard-security-risk","Um curinga CORS é um risco de segurança? Quase nunca.","Um curinga CORS é um risco de segurança? Em geral é o padrão do seu builder e não entrega nada que o seu servidor já não desse a qualquer um que pedisse.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":741,"title":742,"description":743,"published":744,"category":576,"image":745,"draft":526},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching do Supabase não é backup. Ele só anda para a frente.","Por que o branching do Supabase não é backup: um branch começa sem os seus dados e um merge só leva o esquema. Para que ele serve e o que usar no lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":747,"title":748,"description":749,"published":750,"category":576,"image":751,"draft":526},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Como restaurar um backup do Supabase, e o que quebra depois","Como restaurar um backup do Supabase pelo painel ou por um arquivo de dump, o que a restauração substitui e por que o seu app pode continuar quebrado no fim.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":327,"title":753,"description":754,"published":755,"category":522,"image":756,"draft":526},"Seu bucket do Supabase Storage é público. Isso é um problema?","Um bucket público do Supabase Storage significa que quem tem a URL de um arquivo pode abri-lo. Não significa que alguém possa listar o que está lá dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":758,"title":759,"description":760,"published":761,"category":522,"image":762,"draft":526},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Uma chave de API do Google no frontend é um problema?","Uma chave de API do Google exposta no seu frontend é a chave que nosso scanner mais encontra, e quase sempre está tudo bem. Um ajuste gratuito decide isso.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":764,"title":765,"description":766,"published":767,"category":576,"image":768,"draft":526},"\u002Fblog\u002Fai-agent-deleted-my-database","Um agente de IA apagou meus dados do Supabase. O que eu recupero?","Um agente de IA apagou dados do seu banco. O que você recupera já estava decidido antes de ele rodar, e os próximos minutos decidem o resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":265,"title":770,"description":771,"published":772,"category":522,"image":773,"draft":526},"Qualquer um consegue ler seu banco Supabase? Testamos 3.680 apps","Qualquer um consegue ler seu banco de dados Supabase sem fazer login? Escaneamos 30.998 apps no ar criadas com builders de IA e medimos quantas dizem que sim.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":371,"title":775,"description":776,"published":772,"category":522,"image":777,"draft":526},"Source maps expostos: seu app está publicando o código original","Um source map exposto deixa qualquer um ler o código original do seu app, comentários incluídos. A verificação de 30 segundos e o que importa de verdade.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":779,"title":780,"description":781,"published":782,"category":522,"image":783,"draft":526},"\u002Fblog\u002Fsupabase-new-api-keys","As novas chaves de API do Supabase: qual vai no seu app?","O Supabase trocou anon e service_role por chaves publicáveis e secretas. Qual delas pertence ao seu app e qual nunca deve estar lá?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":785,"title":786,"description":787,"published":788,"category":576,"image":789,"draft":526},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","O Supabase faz backup do meu banco de dados? Depende do plano.","O Supabase faz backup do seu banco de dados? Todo dia nos planos pagos, e nada no gratuito. Como descobrir o que você tem e o que essa cópia não cobre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":44,"title":791,"description":792,"published":793,"category":522,"image":794,"draft":526},"O Supabase Row Level Security está ligado. A tabela continua pública.","Ligar o Supabase Row Level Security não protege uma tabela. Quem protege são as políticas, e a que consertou o seu app pode deixar qualquer um entrar.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":796,"title":797,"description":798,"published":793,"category":576,"image":799,"draft":526},"\u002Fblog\u002Fversion-history-is-not-a-backup","O histórico de versões não é backup. Ele não desfaz um delete.","Lovable e Bolt guardam um histórico de versões do seu código. Seu banco de dados é um serviço à parte, e voltar atrás não traz os seus dados de volta.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":801,"title":802,"description":803,"published":804,"category":576,"image":805,"draft":526},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Três formas de fazer backup de um banco Supabase, e o que falta","O painel, o pg_dump e um serviço gerenciado. O que cada um salva de verdade, o que deixa de fora sem avisar e qual sobrevive a perder a conta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":110,"title":807,"description":808,"published":804,"category":522,"image":809,"draft":526},"Quais chaves de API são seguras no navegador e quais não são","Sua chave anon do Supabase foi feita para ser pública. Sua chave service_role não, e ela ignora todas as regras que você criar. Como diferenciar as duas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1790150955877]