[{"data":1,"prerenderedAt":712},["ShallowReactive",2],{"blog-pt-openai-api-key-exposed-in-frontend":3,"blog-index-pt":470},{"id":4,"title":5,"body":6,"category":427,"cover":428,"coverAlt":429,"description":430,"draft":431,"extension":432,"faq":433,"image":449,"keywords":450,"meta":456,"navigation":457,"ogTitle":458,"path":459,"published":460,"seo":461,"stem":462,"tldr":463,"updated":468,"__hash__":469},"blog_pt\u002Fblog\u002Fopenai-api-key-exposed-in-frontend.md","Sua chave de API da OpenAI está exposta no frontend. Troque-a.",{"type":7,"value":8,"toc":413},"minimark",[9,18,26,35,40,43,54,57,60,64,67,82,96,99,103,106,114,117,123,131,134,140,151,154,158,161,164,167,170,174,177,180,185,188,214,217,220,224,242,245,248,253,348,351,367,371,396],[10,11,12,13,17],"p",{},"Abra seu app num navegador, veja o código-fonte da página e procure por\n",[14,15,16],"code",{},"sk-proj-",". Se voltar uma sequência comprida, sua chave de API da OpenAI está\nexposta no seu frontend, e qualquer visitante que você já teve poderia tê-la\ncopiado.",[10,19,20,21,25],{},"Aqui está a parte que quase todo conselho sobre isso erra: ",[22,23,24],"strong",{},"uma chave da OpenAI\nnão é uma chave do Google com outro prefixo, e nada que você configure num painel\na deixa segura onde ela está."," Uma chave do Google Maps tem lugar na sua página,\ne uma configuração gratuita a protege. Uma chave da OpenAI não tem em lugar\nnenhum uma configuração equivalente, e é por isso que a única primeira instrução\nhonesta é trocá-la.",[10,27,28,29,34],{},"Entre 12 e 14 de agosto de 2026 rodamos nove verificações externas em 30.998 apps\nno ar, construídos com Lovable, Bolt, v0, Replit e Base44. Uma chave da OpenAI\napareceu em 33 deles. Os 33 voltaram com nota D ou F, porque um único achado\ncrítico limita a nota por mais que o app tenha acertado no resto. Os números\ncompletos estão no\n",[30,31,33],"a",{"href":32},"\u002Fresearch\u002Fvibe-coded-app-security-2026","nosso relatório de varredura",".",[36,37,39],"h2",{"id":38},"uma-chave-de-api-da-openai-exposta-no-frontend-é-um-problema","Uma chave de API da OpenAI exposta no frontend é um problema?",[10,41,42],{},"Sim. Este é o caso em que o alarme está certo.",[10,44,45,46,49,50,53],{},"Uma chave da OpenAI é um ",[22,47,48],{},"token ao portador",", e a palavra carrega a explicação\ninteira: quem a porta pode usá-la. Ela viaja num cabeçalho que diz\n",[14,51,52],{},"Authorization: Bearer sk-proj-…",", e os servidores da OpenAI não perguntam mais\nnada. Nem qual site a enviou. Nem de que país ela veio, nem se quem manda é você.",[10,55,56],{},"Pense num bilhete de trem, e não num passaporte. Um cobrador não confere de quem\né o nome num bilhete, porque tê-lo é a qualificação inteira. É isso que torna um\nbilhete digno de ser roubado e um passaporte quase nunca.",[10,58,59],{},"Então uma chave impressa no seu app é um bilhete que você entregou a cada\nvisitante. A maioria nunca vai olhar. Quem olha em geral nem é gente: scrapers\nautomáticos varrem páginas públicas coletando sequências em formato de chave, e\nnão precisam saber quem você é para achar a sua.",[36,61,63],{"id":62},"por-que-a-variável-de-ambiente-não-escondeu-a-chave","Por que a variável de ambiente não escondeu a chave",[10,65,66],{},"Porque um build de frontend compila as variáveis de ambiente dentro do arquivo\nque ele publica.",[10,68,69,70,73,74,77,78,81],{},"Este é o passo que deixa as pessoas confiantes de que a chave está protegida.\nVocê tirou a chave do código e pôs num arquivo ",[14,71,72],{},".env",", chamou de\n",[14,75,76],{},"VITE_OPENAI_API_KEY"," ou ",[14,79,80],{},"NEXT_PUBLIC_OPENAI_API_KEY",", e agora o código nomeia\numa variável onde a chave estava. Nada mudou no app publicado. A ferramenta de\nbuild trocou essa variável pelo valor dela na saída, e o valor está no JavaScript\nque o seu visitante baixa.",[10,83,84,85,88,89,91,92,95],{},"A documentação do Vite diz isso sem rodeios: variáveis com o prefixo ",[14,86,87],{},"VITE_","\nficam expostas no código-fonte do lado do cliente depois do bundling, e\ninformações sensíveis como chaves de API não devem estar numa delas, porque os\nvalores são empacotados dentro do seu código-fonte. Os prefixos ",[14,90,87],{}," e\n",[14,93,94],{},"NEXT_PUBLIC_"," não são um cofre. São uma declaração de que você entendeu que essa\nvariável é pública.",[10,97,98],{},"Uma variável de ambiente fez, sim, uma coisa real por você: manteve a chave fora\ndo seu repositório, onde qualquer um que lesse seu código teria topado com ela.\nSeus visitantes nunca leem seu código. Eles leem o arquivo que seu build produziu\na partir dele.",[36,100,102],{"id":101},"por-que-você-não-consegue-restringi-la-como-restringe-uma-chave-do-google","Por que você não consegue restringi-la como restringe uma chave do Google",[10,104,105],{},"Porque a OpenAI não oferece uma restrição desse tipo.",[10,107,108,109,113],{},"Se você leu algo sobre uma chave de API do Google num frontend, encontrou uma\nsolução de cinco minutos: abra a chave no console do Google Cloud, defina uma\nrestrição de referenciador HTTP, e a chave impressa na sua página funciona no seu\nsite e devolve erro em qualquer outro.\n",[30,110,112],{"href":111},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Esse conselho está certo para uma chave do Google",",\ne ele não se transfere.",[10,115,116],{},"Não existe campo numa chave da OpenAI para \"só a partir de yourapp.com\". Nem\nlista de domínios permitidos, nem verificação de referenciador, nem restrição por\nIP que sobreviva a um navegador. O que a OpenAI dá no lugar fica na conta por\ntrás da chave: a qual projeto ela pertence, quanto esse projeto pode gastar no\nmês e se a chave ainda existe. Isso limita quanto uma chave roubada pode custar.\nA chave em si continua funcionando de qualquer lugar até você apagá-la.",[118,119],"diagram",{"alt":120,"caption":121,"src":122},"Duas faixas. Na faixa de cima uma chave do Google sai de dois sites diferentes e encontra uma barreira sólida: o pedido vindo de yourapp.com atravessa e chega ao Google, e o vindo de other.example é parado e marcado com um xis. Na faixa de baixo uma chave da OpenAI sai desses mesmos dois sites, não há barreira nenhuma desenhada, e os dois pedidos chegam a api.openai.com.","A faixa de cima é a solução sobre a qual falam com as pessoas. Na de baixo não há o que desenhar, porque a OpenAI não tem configuração dessa forma.","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fno-gate-to-set-1600x820.png",[36,124,126,127,130],{"id":125},"o-que-dangerouslyallowbrowser-realmente-faz","O que ",[14,128,129],{},"dangerouslyAllowBrowser"," realmente faz",[10,132,133],{},"Desliga uma proteção, e o nome dela é a documentação.",[10,135,136,137,139],{},"A biblioteca JavaScript oficial da OpenAI se recusa a rodar num navegador por\npadrão. O README diz que o suporte a navegador vem\n\"disabled by default to avoid exposing your secret API credentials\", e que ligar\n",[14,138,129],{}," \"can be dangerous because it exposes your secret API\ncredentials in the client-side code\".",[10,141,142,143,146,147,150],{},"Se o seu app chama a OpenAI a partir do navegador, essa opção está como ",[14,144,145],{},"true"," em\nalgum lugar do seu código, porque a biblioteca não inicia sem ela. Alguém digitou\na palavra ",[14,148,149],{},"dangerously"," para calar uma mensagem de erro. É assim que esse achado\ncostuma nascer, e a biblioteca avisou você primeiro.",[10,152,153],{},"A opção tem usos reais, e todos são estreitos: uma ferramenta interna em que você\nconhece cada usuário, uma chave de desenvolvimento temporária, uma chave tão\nlimitada que gastá-la não custa nada. Um app público na internet aberta não é\nnenhum desses.",[36,155,157],{"id":156},"quanto-custa-alguém-achar-sua-chave","Quanto custa alguém achar sua chave",[10,159,160],{},"Uma fatura, e um app que para de funcionar.",[10,162,163],{},"A fatura é a parte que as pessoas esperam. Os pedidos de outra pessoa são\ncobrados da sua conta, e chamadas de modelo não são baratas para o padrão de um\nprojeto paralelo. O jeito comum de quem cuida do app perceber é uma fatura maior\nque a do mês passado sem nenhum motivo que dê para apontar.",[10,165,166],{},"A queda é a parte que ninguém espera. Sua conta tem limites de taxa, e o tráfego\nde um estranho consome esses limites. Seu próprio app começa a devolver erros nas\nhoras em que outra pessoa está trabalhando, e isso se lê como bug e não como\nroubo, então passa-se um dia depurando a coisa errada.",[10,168,169],{},"Há um terceiro custo, e ele depende de quão ampla era a chave. Uma chave de API\nautentica toda chamada que o projeto a que ela pertence pode fazer, então uma\nchave com permissões amplas alcança tudo o mais que estiver guardado ali:\narquivos enviados para a conta, modelos ajustados, assistentes que você\nconstruiu. Verifique o que a chave conseguia de fato alcançar antes de decidir\nque isso era só sobre dinheiro.",[36,171,173],{"id":172},"como-chamar-a-openai-do-seu-app-sem-publicar-a-chave","Como chamar a OpenAI do seu app sem publicar a chave",[10,175,176],{},"Coloque algo seu entre o seu visitante e a OpenAI.",[10,178,179],{},"O formato é o mesmo em todo lugar. Seu app chama um pequeno endpoint que é seu.\nEsse endpoint guarda a chave, chama a OpenAI e devolve a resposta. O navegador\nnunca vê a chave, porque a chave nunca sai do seu servidor.",[118,181],{"alt":182,"caption":183,"src":184},"Duas linhas. Na linha de cima um painel de navegador guarda um valor de chave em vermelho e uma linha sai dali direto para api.openai.com. Na linha de baixo o painel do navegador não guarda chave nenhuma, uma linha vai até uma caixa de servidor que guarda a chave em verde-água, e uma segunda linha segue do servidor para api.openai.com.","O mesmo pedido nas duas linhas. O que muda é de que lado do seu próprio servidor a chave está.","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fwho-holds-the-key-1600x720.png",[10,186,187],{},"Onde esse endpoint mora depende do que você usou para construir:",[189,190,191,198,208],"ul",{},[192,193,194,197],"li",{},[22,195,196],{},"Supabase na sua stack",": uma Edge Function, com a chave guardada como secret no painel do Supabase.",[192,199,200,203,204,207],{},[22,201,202],{},"Publicado na Vercel ou na Netlify",": uma função serverless em ",[14,205,206],{},"\u002Fapi",", com a chave nas variáveis de ambiente de servidor do projeto.",[192,209,210,213],{},[22,211,212],{},"Lovable, Bolt ou Replit",": cada um tem seu próprio cofre de secrets. A regra não muda, e a armadilha também não: um cofre rotulado como secrets manda o valor para o navegador do mesmo jeito se o código que o lê roda lá.",[10,215,216],{},"Duas coisas valem a pena enquanto você está por lá. Dê ao seu endpoint um limite\nde taxa, porque um endpoint que chama a OpenAI para qualquer um que pedir é a\nmesma fatura por um caminho mais lento. E coloque um limite de gasto mensal no\nprojeto da OpenAI, o único controle que põe um piso sob o pior caso.",[10,218,219],{},"Se o seu app usa a Realtime API da OpenAI para voz, o navegador precisa mesmo de\numa credencial, e a OpenAI documenta como dar uma a ele: seu servidor cunha um\nclient secret de vida curta e entrega esse à página. O bilhete continua\nexistindo, expira em minutos, e foi o seu próprio servidor que o emitiu.",[36,221,223],{"id":222},"como-achar-de-graça-toda-chave-que-seu-app-publica","Como achar de graça toda chave que seu app publica",[10,225,226,227,229,230,233,234,237,238,241],{},"Comece na mão, porque custa cinco minutos e não exige instalar nada. Veja o\ncódigo-fonte do seu site no ar e procure ",[14,228,16],{}," para uma chave da OpenAI,\n",[14,231,232],{},"sk-ant-"," para uma da Anthropic, ",[14,235,236],{},"AIza"," para o Google e ",[14,239,240],{},"eyJ"," para um token do\nSupabase.",[10,243,244],{},"O que escapa assim é o JavaScript que a página carrega depois, que num app feito\ncom vibe coding é quase tudo. Nosso scanner abre seu app num navegador de\nverdade, espera os bundles chegarem e lê esses em vez do HTML. Ele também\ndecodifica cada token do Supabase e informa o papel escrito dentro dele, de modo\nque uma chave que tem lugar na sua página volta marcada como correta e não\nenterrada numa parede de vermelho.",[10,246,247],{},"A verificação de chaves é uma de nove, e as outras oito são o motivo pelo qual\numa nota diz mais do que uma busca:",[118,249],{"alt":250,"caption":251,"src":252},"A marca da Reeve acima de uma fileira de nove ícones de contorno, um por verificação: uma chave, um cilindro de banco de dados, um documento, um cadeado, uma caixa com tampa, um par de colchetes de código, um globo, uma roseta de certificado e um calendário.","As nove verificações somente de leitura que uma varredura faz, na ordem da lista abaixo. Cada uma é lida de fora, do jeito que um estranho vê seu app.","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fnine-checks-1600x420.png",[254,255,256,269],"table",{},[257,258,259],"thead",{},[260,261,262,266],"tr",{},[263,264,265],"th",{},"O que a varredura olha",[263,267,268],{},"A pergunta que ela responde",[270,271,272,281,289,300,308,316,324,332,340],"tbody",{},[260,273,274,278],{},[275,276,277],"td",{},"Chaves secretas no seu código",[275,279,280],{},"Há uma chave de API paga ou de admin legível por qualquer um?",[260,282,283,286],{},[275,284,285],{},"Regras do banco de dados",[275,287,288],{},"Um estranho consegue ler as linhas dos seus usuários sem login?",[260,290,291,294],{},[275,292,293],{},"Arquivos privados",[275,295,296,297,299],{},"Arquivos ",[14,298,72],{}," ou dumps do banco podem ser baixados por uma URL?",[260,301,302,305],{},[275,303,304],{},"Cabeçalhos de segurança",[275,306,307],{},"As proteções do lado do navegador estão ligadas?",[260,309,310,313],{},[275,311,312],{},"Buckets de armazenamento",[275,314,315],{},"Qualquer um consegue listar os arquivos que seus usuários enviam?",[260,317,318,321],{},[275,319,320],{},"Source maps",[275,322,323],{},"Seu código-fonte original está publicado junto com o app?",[260,325,326,329],{},[275,327,328],{},"APIs abertas e CORS",[275,330,331],{},"Seus endpoints respondem a qualquer site que pedir?",[260,333,334,337],{},[275,335,336],{},"Validade do certificado",[275,338,339],{},"O HTTPS é válido e não está prestes a vencer nos seus visitantes?",[260,341,342,345],{},[275,343,344],{},"Renovação do domínio",[275,346,347],{},"O nome está renovado antes que outra pessoa possa tomá-lo?",[10,349,350],{},"Você recebe uma nota, uma pontuação e as contagens na tela em cerca de 20\nsegundos, sem conta. Dê um endereço de e-mail e a lista detalhada vem junto, com\numa correção escrita para o seu builder que dá para colar direto.",[10,352,353,354,357,358,362,363,34],{},"Três coisas que ele não vai fazer, e são os motivos pelos quais é seguro apontá-lo\npara um app no ar: ele nunca faz login, nunca escreve nada e nunca guarda uma\nchave que encontra. Um segredo exposto é guardado como uma dica mascarada no\nformato ",[14,355,356],{},"sk-proj-…a1b2",", e o valor real é descartado.\n",[30,359,361],{"href":360},"\u002F#scan","Escaneie seu app",", ou leia antes\n",[30,364,366],{"href":365},"\u002Fsecurity-scanner","o que cada uma das nove verificações olha",[36,368,370],{"id":369},"o-que-fazer-agora","O que fazer agora",[372,373,374],"key-takeaways",{},[189,375,376,379,382,385,388],{},[192,377,378],{},"Troque a chave primeiro, no painel da OpenAI em API keys. Apagá-la do seu código não fecha nada, porque o valor antigo continua no seu histórico de versões e em cada cópia em cache da sua página.",[192,380,381],{},"Coloque um limite de gasto mensal no projeto a que a chave pertence. É o único controle que põe um teto no que este erro, ou um próximo, pode lhe custar.",[192,383,384],{},"Mova a chamada para trás de um endpoint seu, e dê a esse endpoint um limite de taxa próprio. Um navegador nunca deveria guardar uma chave que gasta dinheiro.",[192,386,387],{},"Leia sua página de uso nos dias em que a chave esteve ativa. Trocar a chave interrompe o que vem a seguir e não diz nada sobre o que já aconteceu.",[192,389,390,391,77,393,395],{},"Mantenha o prefixo ",[14,392,87],{},[14,394,94],{}," longe de tudo o que você não gostaria que um estranho lesse. Esses prefixos querem dizer público, e sua ferramenta de build os leva ao pé da letra.",[10,397,398,399,403,404,408,409,34],{},"Se você prefere resolver tudo de uma vez, a\n",[30,400,402],{"href":401},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre isso junto com as outras\ncoisas que vale fechar num app recém-lançado. E para a pergunta mais ampla sobre\nquais chaves têm lugar num navegador, temos\n",[30,405,407],{"href":406},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","um guia para diferenciar chaves publicáveis das secretas","\ne\n",[30,410,412],{"href":411},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","um censo do que 30.998 apps realmente publicaram",{"title":414,"searchDepth":415,"depth":415,"links":416},"",3,[417,419,420,421,423,424,425,426],{"id":38,"depth":418,"text":39},2,{"id":62,"depth":418,"text":63},{"id":101,"depth":418,"text":102},{"id":125,"depth":418,"text":422},"O que dangerouslyAllowBrowser realmente faz",{"id":156,"depth":418,"text":157},{"id":172,"depth":418,"text":173},{"id":222,"depth":418,"text":223},{"id":369,"depth":418,"text":370},"Noções de segurança","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcover-1200x630.png","Um valor em formato de chave dentro de uma página de código de app, desenhado comprido o bastante para passar da borda direita do painel que o segura.","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.",false,"md",[434,437,440,443,446],{"q":435,"a":436},"Alguém achou minha chave da OpenAI no meu app. Qual é a primeira coisa a fazer?","Trocá-la. Abra seu painel da OpenAI em API keys, crie uma chave nova, coloque a nova no seu servidor e apague a antiga. Apagá-la do seu código não é a mesma coisa, porque o valor antigo continua no seu histórico de versões e em qualquer cópia em cache da sua página. Depois coloque um limite de gasto no projeto e leia sua página de uso nos dias em que a chave esteve ativa.",{"q":438,"a":439},"Posso restringir uma chave da OpenAI ao meu domínio, como faço com uma do Google?","Não. Uma chave de API do Google aceita uma restrição de referenciador HTTP que a faz funcionar no seu site e falhar em todos os outros, e é por isso que uma chave do Google na sua página costuma ser inofensiva. A OpenAI não oferece nada equivalente. Não há lista de domínios permitidos nem verificação de referenciador numa chave de API, então os únicos controles que você tem ficam na conta por trás dela: a qual projeto a chave pertence, quanto esse projeto pode gastar e se a chave ainda existe.",{"q":441,"a":442},"A biblioteca da OpenAI tem uma opção dangerouslyAllowBrowser. Isso deixa a chave segura?","Não, e o nome é o aviso. A OpenAI entrega o suporte a navegador desligado, e o próprio README diz que a opção é perigosa porque expõe suas credenciais secretas de API no código do lado do cliente. Ligá-la não muda o que o navegador consegue ler; só impede a biblioteca de se recusar a iniciar. Os casos estreitos para os quais ela foi pensada são ferramentas internas com usuários conhecidos e chaves de desenvolvimento de vida curta, não um app público.",{"q":444,"a":445},"Quanto alguém consegue gastar com uma chave que encontrou?","Tudo o que sua conta permitir, e é por isso que o limite de gasto importa mais do que o tamanho da fatura que você já viu. Uma chave roubada consome os mesmos limites de taxa que o seu app usa, então o primeiro sintoma muitas vezes nem é a fatura: é o seu próprio app começando a falhar enquanto outra pessoa está trabalhando. Coloque um limite de gasto mensal no projeto e você tem um teto para tudo isso.",{"q":447,"a":448},"Usei a chave só para uma demo rápida. Ainda assim importa?","Sim. Uma chave fica ativa até alguém revogá-la, e ela não sabe que deveria ser temporária. Scrapers automáticos coletam sem parar sequências em formato de chave em páginas públicas, então a idade da demo joga contra você e não a seu favor. Apagar a chave leva menos tempo do que decidir se valia a pena apagá-la.","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",[451,452,453,454,129,455],"chave api openai exposta frontend","esconder chave api openai no react","chamar a openai do frontend com segurança","segurança da chave api openai","chave api openai vazada",{},true,"Chave de API da OpenAI exposta no seu frontend?","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","2026-09-03",{"title":5,"description":430},"blog\u002Fopenai-api-key-exposed-in-frontend",[464,465,466,467],"Uma chave de API da OpenAI exposta no seu frontend é o caso em que o alarme está certo. Nenhuma configuração deixa uma chave dessas segura dentro de um navegador.","Ela é um token ao portador, então basta tê-la em mãos. Não existe restrição de domínio que a prenda ao seu próprio site, como existe para uma chave do Google.","Troque-a hoje no painel da OpenAI, mova a chamada para trás de um endpoint seu e coloque um limite de gasto no projeto.","Encontramos uma em 33 de 30.998 apps escaneados. Raro, e as 33 saíram com nota D ou F.","2026-09-21","mgFupsYXrsZlK6HRy8gdf-vp4aaS5PQEXa-_jVrScH8",[471,478,484,489,495,501,507,513,519,525,531,537,543,549,555,561,567,573,579,585,591,592,597,603,609,615,621,627,633,639,645,651,657,662,668,674,679,685,691,697,702,708],{"path":472,"title":473,"description":474,"published":475,"category":476,"image":477,"draft":431},"\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":479,"title":480,"description":481,"published":482,"category":427,"image":483,"draft":431},"\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":485,"title":486,"description":487,"published":468,"category":427,"image":488,"draft":431},"\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.","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":490,"title":491,"description":492,"published":493,"category":427,"image":494,"draft":431},"\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":496,"title":497,"description":498,"published":499,"category":427,"image":500,"draft":431},"\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":502,"title":503,"description":504,"published":505,"category":427,"image":506,"draft":431},"\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":508,"title":509,"description":510,"published":511,"category":427,"image":512,"draft":431},"\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":514,"title":515,"description":516,"published":517,"category":427,"image":518,"draft":431},"\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":520,"title":521,"description":522,"published":523,"category":427,"image":524,"draft":431},"\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":526,"title":527,"description":528,"published":529,"category":476,"image":530,"draft":431},"\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":532,"title":533,"description":534,"published":535,"category":476,"image":536,"draft":431},"\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":538,"title":539,"description":540,"published":541,"category":476,"image":542,"draft":431},"\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":544,"title":545,"description":546,"published":547,"category":427,"image":548,"draft":431},"\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":550,"title":551,"description":552,"published":553,"category":427,"image":554,"draft":431},"\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":556,"title":557,"description":558,"published":559,"category":427,"image":560,"draft":431},"\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":562,"title":563,"description":564,"published":565,"category":427,"image":566,"draft":431},"\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":568,"title":569,"description":570,"published":571,"category":427,"image":572,"draft":431},"\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":574,"title":575,"description":576,"published":577,"category":427,"image":578,"draft":431},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: faça você mesmo as cinco verificações","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.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":580,"title":581,"description":582,"published":583,"category":427,"image":584,"draft":431},"\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":586,"title":587,"description":588,"published":589,"category":427,"image":590,"draft":431},"\u002Fblog\u002Fmissing-security-headers","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":459,"title":5,"description":430,"published":460,"category":427,"image":449,"draft":431},{"path":411,"title":593,"description":594,"published":595,"category":427,"image":596,"draft":431},"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":598,"title":599,"description":600,"published":601,"category":476,"image":602,"draft":431},"\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":604,"title":605,"description":606,"published":607,"category":427,"image":608,"draft":431},"\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":610,"title":611,"description":612,"published":613,"category":476,"image":614,"draft":431},"\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":616,"title":617,"description":618,"published":619,"category":427,"image":620,"draft":431},"\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":622,"title":623,"description":624,"published":625,"category":427,"image":626,"draft":431},"\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":628,"title":629,"description":630,"published":631,"category":427,"image":632,"draft":431},"\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":634,"title":635,"description":636,"published":637,"category":427,"image":638,"draft":431},"\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":640,"title":641,"description":642,"published":643,"category":476,"image":644,"draft":431},"\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":646,"title":647,"description":648,"published":649,"category":476,"image":650,"draft":431},"\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":652,"title":653,"description":654,"published":655,"category":427,"image":656,"draft":431},"\u002Fblog\u002Fsupabase-storage-bucket-public","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":111,"title":658,"description":659,"published":660,"category":427,"image":661,"draft":431},"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":663,"title":664,"description":665,"published":666,"category":476,"image":667,"draft":431},"\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":669,"title":670,"description":671,"published":672,"category":427,"image":673,"draft":431},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","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":675,"title":676,"description":677,"published":672,"category":427,"image":678,"draft":431},"\u002Fblog\u002Fsource-maps-exposed-in-production","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":680,"title":681,"description":682,"published":683,"category":427,"image":684,"draft":431},"\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":686,"title":687,"description":688,"published":689,"category":476,"image":690,"draft":431},"\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":692,"title":693,"description":694,"published":695,"category":427,"image":696,"draft":431},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","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":698,"title":699,"description":700,"published":695,"category":476,"image":701,"draft":431},"\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":703,"title":704,"description":705,"published":706,"category":476,"image":707,"draft":431},"\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":406,"title":709,"description":710,"published":706,"category":427,"image":711,"draft":431},"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",1790150955886]