[{"data":1,"prerenderedAt":1184},["ShallowReactive",2],{"blog-pt-permission-denied-for-schema-public":3,"blog-index-pt":653},{"id":4,"title":5,"body":6,"category":612,"cover":613,"coverAlt":614,"description":615,"draft":616,"extension":617,"faq":618,"image":634,"keywords":635,"meta":642,"navigation":643,"ogTitle":5,"path":644,"published":645,"seo":646,"stem":647,"tldr":648,"updated":645,"__hash__":652},"blog_pt\u002Fblog\u002Fpermission-denied-for-schema-public.md","Supabase \"permission denied for schema public\": três causas",{"type":7,"value":8,"toc":598},"minimark",[9,18,21,31,38,46,51,57,87,102,116,125,131,134,138,154,163,166,172,183,187,192,199,205,214,217,221,224,230,240,243,250,253,269,274,277,281,287,299,302,306,316,344,357,361,364,367,373,399,405,425,431,447,451,454,486,493,497,500,509,527,536,553,557,592],[10,11,12,13,17],"p",{},"Ontem o seu app funcionava. Hoje cada tela que lê do Supabase aparece vazia ou\nmostra um erro, e o console do navegador tem a mesma linha para todas:\n",[14,15,16],"code",{},"permission denied for schema public",". Você abre o painel do Supabase e todas as\ntabelas continuam lá. O SQL Editor lê todas sem reclamar.",[10,19,20],{},"A resposta por trás dessa linha costuma chegar como 401 ou 403. Cortada nos dois\ncampos que importam, ela diz isto:",[22,23,28],"pre",{"className":24,"code":26,"language":27},[25],"language-text","{\n  \"code\": \"42501\",\n  \"message\": \"permission denied for schema public\"\n}\n","text",[14,29,26],{"__ignoreMap":30},"",[10,32,33,34,37],{},"Supabase \"permission denied for schema public\" vem do Postgres, o banco de dados\nem que o Supabase roda, e a lista de causas é curta. Todo projeto do Supabase é\ncriado com um grant que deixa o seu app entrar no schema ",[14,35,36],{},"public",". Alguém, ou\nalgo, tirou esse grant, e devolvê-lo é uma linha de SQL.",[10,39,40,41,45],{},"Esta é a parte fácil de entender ao contrário: ",[42,43,44],"strong",{},"esse grant é a porta da frente\ndo prédio, e as fechaduras dos seus dados ficam mais para dentro."," Se alguém o\ntirou para deixar estranhos do lado de fora, deixou o seu app de fora junto. E\nreabrir essa porta só é seguro se as fechaduras de dentro estiverem no lugar,\nentão são elas que você precisa conferir antes de dar o problema por resolvido.",[47,48,50],"h2",{"id":49},"o-que-significa-permission-denied-for-schema-public","O que significa \"permission denied for schema public\"?",[10,52,53,54,56],{},"Significa que a função que faz a requisição não tem o direito de entrar no\nschema ",[14,55,36],{},", então o Postgres recusou antes de olhar uma única tabela.",[10,58,59,60,63,64,66,67,70,71,74,75,78,79,82,83,86],{},"Um ",[42,61,62],{},"schema"," é uma pasta de tabelas com nome dentro do seu banco de dados.\n",[14,65,36],{}," é onde Lovable, Bolt, v0, Cursor, Claude Code e Replit colocam as suas\ntabelas se ninguém disser outra coisa. Uma ",[42,68,69],{},"função"," (role, em inglês) é o\ntipo de visitante de onde vem uma requisição: ",[14,72,73],{},"anon"," é alguém que não fez login,\n",[14,76,77],{},"authenticated"," é alguém que fez, e ",[14,80,81],{},"service_role"," é o seu próprio código de\nservidor usando a chave secreta. Um ",[42,84,85],{},"grant"," dá a uma função uma permissão sobre\numa coisa.",[10,88,89,90,93,94,101],{},"A permissão de que esse erro fala se chama ",[14,91,92],{},"USAGE",", e a\n",[95,96,100],"a",{"href":97,"rel":98},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-priv.html",[99],"nofollow","documentação do Postgres","\na descreve como o direito de procurar (\"look up\") objetos dentro do schema. Uma\nfunção sem ela não alcança nenhuma tabela desse schema, não importa o que digam\nas configurações da própria tabela.",[10,103,104,105,109,110,112,113,115],{},"Se ",[95,106,108],{"href":107},"\u002Fblog\u002Fsupabase-permission-denied-for-table","a versão de tabela deste erro","\nensinou você a pensar em cada tabela como uma sala com uma porta para cada\nfunção, o schema é o prédio onde ficam essas salas, e ",[14,111,92],{}," é a porta da\nfrente dele. ",[14,114,16],{}," significa que a sua\nrequisição está parada do lado de fora. Não importa quais salas estão com a\nporta aberta, porque a requisição nunca chega a uma sala.",[10,117,118,119,124],{},"O Supabase dá essa porta da frente às três funções quando um projeto é criado.\nA ",[95,120,123],{"href":121,"rel":122},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fpostgres\u002Fblob\u002Fdevelop\u002Fmigrations\u002Fdb\u002Finit-scripts\u002F00000000000000-initial-schema.sql",[99],"imagem de banco de dados do próprio Supabase","\nexecuta esta linha no primeiro script de configuração:",[22,126,129],{"className":127,"code":128,"language":27},[25],"grant usage on schema public to postgres, anon, authenticated, service_role;\n",[14,130,128],{"__ignoreMap":30},[10,132,133],{},"Então, se o seu app recebe esse erro, o grant existiu e não existe mais.",[47,135,137],{"id":136},"por-que-o-sql-editor-continua-funcionando","Por que o SQL Editor continua funcionando?",[10,139,140,141,146,147,150,151,153],{},"Porque o SQL Editor não usa nenhuma das funções do seu app. Um\n",[95,142,145],{"href":143,"rel":144},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Ftracking-postgres-role-activity-to-specific-dashboard-users-8d3715",[99],"guia de solução de problemas do Supabase","\ndiz que uma consulta feita ali é \"routed through the ",[14,148,149],{},"postgres"," role at the\ndatabase level\", ou seja, passa pela função ",[14,152,149],{}," no nível do banco de\ndados.",[10,155,156,158,159,162],{},[14,157,149],{}," é a função dona das suas tabelas, e se o próprio schema foi recriado\npelo painel ou pelo seu builder, ela é dona dele também. Quem é dono não precisa\nde grant para entrar no próprio prédio. Por isso o painel mostra todas as\ntabelas, um ",[14,160,161],{},"select"," no SQL Editor devolve todas as linhas, e a mesma\nrequisição vinda do seu app é barrada na porta da frente. Nada nessas telas\navisa que as funções do seu app perderam o caminho para entrar.",[10,164,165],{},"Para ver o que o seu app vê, pergunte ao Postgres diretamente sobre as funções\ndele. Cole isto no SQL Editor:",[22,167,170],{"className":168,"code":169,"language":27},[25],"select rolname,\n       has_schema_privilege(rolname, 'public', 'USAGE') as can_enter\nfrom pg_roles\nwhere rolname in ('anon', 'authenticated', 'service_role');\n",[14,171,169],{"__ignoreMap":30},[10,173,174,175,178,179,182],{},"Cada linha deveria dizer ",[14,176,177],{},"true",". Uma linha que diz ",[14,180,181],{},"false"," é uma função que o\nseu app usa e que não consegue mais entrar.",[47,184,186],{"id":185},"o-grant-abre-o-prédio-e-as-fechaduras-ficam-lá-dentro","O grant abre o prédio, e as fechaduras ficam lá dentro",[10,188,189,191],{},[14,190,92],{}," deixa uma função chegar às tabelas de um schema. Ele não diz nada sobre\nquais dessas tabelas a função pode usar, nem quais linhas ela recebe.",[10,193,194,195,198],{},"Atrás da porta da frente há mais duas verificações, e as duas pertencem a cada\ntabela. O grant próprio da tabela decide se uma função pode usar aquela tabela,\ne quando ele falta é isso que ",[14,196,197],{},"permission denied for table"," informa. Depois, o\nRow Level Security, as regras por linha que você talvez já conheça, decide\nquais linhas essa função recebe. O Postgres faz as três perguntas nessa ordem e\npara na primeira recusa.",[200,201],"diagram",{"alt":202,"caption":203,"src":204},"Três faixas, cada uma uma requisição de anon indo para a mesma tabela. Na primeira, um portão gradeado marcado public está fechado e a seta para nele com o código 42501, antes da porta da própria tabela. Na segunda, o portão está aberto e a seta para na porta fechada da tabela, também 42501. Na terceira, portão e porta estão abertos, a seta para numa barreira de Row Level Security e duas linhas da tabela se acendem.","O Postgres verifica o schema, depois a tabela, depois as linhas, e para na primeira recusa. Um portão fechado barra a requisição antes que a porta de qualquer tabela seja sequer tentada.","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fthree-checks-in-order-1600x760.png",[10,206,207,208,210,211,213],{},"É essa ordem que faz do grant do schema uma fechadura ruim. Para uma função, ele\né tudo ou nada: tire-o de ",[14,209,73],{}," e cada tela que um visitante sem login vê para\nde funcionar de uma vez, inclusive uma página de login que leia qualquer coisa\ndas suas tabelas. Tire-o de ",[14,212,77],{}," e o mesmo acontece com todo mundo\nque fez login. A documentação do Postgres acrescenta que revogá-lo \"is not a\ncompletely secure way to prevent object access\", ou seja, não é um jeito\ntotalmente seguro de impedir o acesso, e que uma função sem ele ainda consegue\nler os nomes das suas tabelas nos catálogos do sistema.",[10,215,216],{},"Se você está vendo esse erro, o seu app precisa da função que foi recusada.",[47,218,220],{"id":219},"causa-1-o-schema-foi-apagado-e-criado-de-novo","Causa 1: o schema foi apagado e criado de novo",[10,222,223],{},"Essa é a causa que leva mais coisa junto. Alguém executou estas duas linhas, ou\nalgo que faz o mesmo:",[22,225,228],{"className":226,"code":227,"language":27},[25],"drop schema public cascade;\ncreate schema public;\n",[14,229,227],{"__ignoreMap":30},[10,231,232,233,236,237,239],{},"A primeira linha remove o schema e, por causa do ",[14,234,235],{},"cascade",", toda tabela, view e\nfunção que havia dentro dele. A segunda cria um ",[14,238,36],{}," novo e vazio. Um schema\nnovo pertence à função que o criou, e a documentação do Postgres é clara: por\npadrão, ninguém mais recebe privilégio algum sobre um schema. O grant que o\nSupabase executou quando criou o seu projeto pertencia ao schema antigo e foi\nembora com ele, e o Supabase não executa o script de configuração uma segunda\nvez.",[10,241,242],{},"Essas duas linhas são o jeito mais curto de esvaziar um banco Postgres, e por\nisso são um passo que um assistente de IA pode dar quando você pede para começar\no banco do zero ou para fazer uma migração que está falhando passar limpa.",[10,244,245,246,249],{},"Depois disso, as suas tabelas voltam se as migrações do app rodarem de novo. Uma\n",[42,247,248],{},"migração"," é um dos arquivos de mudanças no banco que o seu builder escreve, e\nrodar todas reconstrói as tabelas que elas descrevem. O que não volta é tudo o\nque elas nunca mencionam, e o grant da porta da frente foi feito pelo Supabase\nantes de existir a sua primeira migração. As migrações que o seu builder\nescreveu podem nem conter esse grant.",[10,251,252],{},"Mais duas coisas vão embora com o schema antigo:",[254,255,256,263],"ul",{},[257,258,259,262],"li",{},[42,260,261],{},"Os grants automáticos para tabelas novas."," O Postgres guarda esses grants\ncomo privilégios padrão (default privileges) do schema, e eles são apagados\njunto com ele. As tabelas criadas depois começam sem grant para nenhuma das\nfunções do seu app.",[257,264,265,268],{},[42,266,267],{},"As linhas."," Migrações reconstroem tabelas vazias. O que havia nas antigas\nsó volta se alguém restaurou uma cópia feita antes do reset.",[200,270],{"alt":271,"caption":272,"src":273},"Dois pátios murados lado a lado, ambos marcados public. À esquerda, o schema original: portão aberto, três tabelas com as portas abertas e as linhas acesas, e em cima etiquetas para postgres, anon, authenticated e service_role. À direita, o schema recriado: as mesmas três tabelas com as portas fechadas, o portão fechado, só a etiqueta postgres ainda acesa e contornos tracejados onde estavam as outras três.","Antes do reset, as quatro funções podiam entrar no schema. Depois, as tabelas podem ser reconstruídas, mas o portão e as portas delas só abrem para postgres, que as construiu.","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fdrop-and-create-1600x700.png",[10,275,276],{},"Se as suas tabelas voltaram vazias, encontrar essa cópia vem antes de qualquer\noutra coisa nesta página.",[47,278,280],{"id":279},"causa-2-um-revoke-feito-para-proteger","Causa 2: um revoke feito para proteger",[10,282,283,284,286],{},"O segundo jeito é de propósito. Alguém leu que toda tabela em ",[14,285,36],{}," pode ser\nacessada pela Data API do Supabase, o endereço web pelo qual o seu app lê e\ngrava os dados, e revogou o grant do schema para fechar isso.",[10,288,289,290,295,296,298],{},"A preocupação por trás disso é razoável, e a ferramenta escolhida é a errada. O\nguia do próprio Supabase para\n",[95,291,294],{"href":292,"rel":293},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fapi\u002Fsecuring-your-api",[99],"proteger a Data API","\nnunca mexe no grant do schema. O que ele revoga é o acesso automático que as\ntabelas novas de ",[14,297,36],{}," recebem, de modo que cada tabela nova continua fechada\naté alguém dar acesso a ela de propósito. O Supabase liga isso para todos os\nprojetos existentes em 30 de outubro de 2026.",[10,300,301],{},"Se um script que você rodou, ou um assistente a quem você pediu para reforçar o\nbanco, tirou o grant do schema, a consulta de verificação acima mostra quais\nfunções o perderam. Devolva o grant às que o seu app usa e depois faça a\nproteção do jeito que as seções abaixo descrevem.",[47,303,305],{"id":304},"causa-3-o-erro-vem-de-uma-migração","Causa 3: o erro vem de uma migração",[10,307,308,309,312,313,315],{},"Quando a mensagem aparece enquanto algo está criando tabelas, como uma\nmigração, um deploy, ou o Prisma ou o Drizzle preparando o seu banco, a\npermissão que falta é outra. Criar qualquer coisa num schema exige ",[14,310,311],{},"CREATE","\nnele, e o texto do erro quando falta ",[14,314,311],{}," é a mesma linha.",[10,317,318,319,321,322,324,325,329,330,335,336,339,340,343],{},"Desde o Postgres 15, funções comuns não recebem mais ",[14,320,311],{}," em ",[14,323,36],{}," por\npadrão. A\n",[95,326,100],{"href":327,"rel":328},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-schemas.html",[99],"\ndiz que só bancos atualizados a partir da versão 14 ou anterior ainda dão isso a\ntodo mundo. Por isso um usuário de banco separado, criado para uma ferramenta de\nmigração, é recusado já na primeiríssima tabela. O\n",[95,331,334],{"href":332,"rel":333},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fdatabase\u002Fprisma",[99],"guia do Prisma"," do Supabase\ncria um usuário ",[14,337,338],{},"prisma",", e a configuração dele inclui\n",[14,341,342],{},"grant create on schema public to prisma",".",[10,345,346,347,350,351,353,354,356],{},"A solução é um grant de ",[14,348,349],{},"create"," só para esse usuário de migração. Ninguém que\nvisita o seu app precisa criar tabelas, então ",[14,352,73],{}," e ",[14,355,77],{}," nunca\nrecebem um.",[47,358,360],{"id":359},"como-devolver-o-grant-com-segurança","Como devolver o grant com segurança",[10,362,363],{},"Execute uma linha, confirme que as três funções conseguem entrar, depois\nrecarregue o seu app e leia o que ele diz em seguida.",[10,365,366],{},"A linha, no SQL Editor:",[22,368,371],{"className":369,"code":370,"language":27},[25],"grant usage on schema public to anon, authenticated, service_role;\n",[14,372,370],{"__ignoreMap":30},[10,374,375,376,379,380,383,384,387,388,390,391,393,394,398],{},"Fique no ",[14,377,378],{},"usage",". ",[14,381,382],{},"grant all on schema public"," também acaba com o erro, e num\nschema ",[14,385,386],{},"all"," quer dizer ",[14,389,378],{}," mais ",[14,392,349],{},", o direito de adicionar tabelas\npróprias. O Supabase recomenda dar a cada função\n",[95,395,397],{"href":292,"rel":396},[99],"o mínimo de que ela precisa",",\ne as funções dos seus visitantes só precisam entrar.",[10,400,401,402,404],{},"A consulta de verificação de antes agora deveria dizer ",[14,403,177],{}," para as três\nfunções. Recarregue o seu app, e uma de duas coisas acontece:",[254,406,407,413],{},[257,408,409,412],{},[42,410,411],{},"Ele funciona."," A porta da frente era a única coisa que faltava.",[257,414,415,418,419,421,422,343],{},[42,416,417],{},"Uma mensagem nova cita uma tabela."," ",[14,420,197],{}," significa\nque o grant próprio dessa tabela também está faltando, o que é de esperar\ndepois da primeira causa, porque tabelas reconstruídas nunca receberam os\ngrants automáticos. Dê a cada tabela\n",[95,423,424],{"href":107},"o grant dela, o Row Level Security e uma regra numa única mudança",[10,426,427,428,430],{},"Resista à tentação de dar tudo em todas as tabelas para todas as funções só\npara a segunda mensagem sumir. Uma tabela com grant para ",[14,429,73],{}," e Row Level\nSecurity desligado entrega todas as linhas a qualquer um que pedir, e nada no\nseu app vai parecer diferente.",[10,432,433,434,437,438,440,441,446],{},"Se a mensagem cita outro schema, como ",[14,435,436],{},"permission denied for schema api",", esse\nschema foi criado por alguém e nunca recebeu os grants com que ",[14,439,36],{}," começa.\nO guia do Supabase para\n",[95,442,445],{"href":443,"rel":444},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fapi\u002Fusing-custom-schemas",[99],"usar schemas personalizados","\nlista as linhas de que ele precisa.",[47,448,450],{"id":449},"o-que-proteger-no-lugar","O que proteger no lugar",[10,452,453],{},"Os controles que mantêm estranhos longe dos seus dados pertencem a cada tabela,\ne o guia de segurança do Supabase cita todos:",[455,456,457,465,474,480],"ol",{},[257,458,459,462,463,343],{},[42,460,461],{},"Um grant por tabela, para as funções que precisam dele."," Uma tabela de\npedidos não precisa de grant nenhum para ",[14,464,73],{},[257,466,467,470,343],{},[42,468,469],{},"Row Level Security em toda tabela, com uma regra.",[95,471,473],{"href":472},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Como ligar e conferir se ele segura",[257,475,476,479],{},[42,477,478],{},"Tabelas novas fechadas por padrão."," Revogar os grants automáticos faz isso\nhoje, e o 30 de outubro faz isso por você.",[257,481,482,485],{},[42,483,484],{},"Tabelas internas fora da Data API."," O guia do Supabase descreve como\ncolocar o que o seu app lê num schema dedicado, para que todo o resto fique em\nschemas que a Data API não serve.",[10,487,488,489,343],{},"Depois olhe o resultado de fora, porque nenhuma dessas telas mostra o que um\nestranho recebe. O nosso scan gratuito pergunta a cada tabela que o seu\napp cita quantas linhas um visitante sem login receberia, lê esse número sem\nbaixar uma única linha e leva uns 20 segundos, sem conta:\n",[95,490,492],{"href":491},"\u002Fsecurity-scanner","escaneie seu app",[47,494,496],{"id":495},"mantendo-as-suas-tabelas-e-o-que-há-nelas","Mantendo as suas tabelas, e o que há nelas",[10,498,499],{},"Depois de hoje, ainda podem dar errado duas coisas: uma mudança posterior abre\numa tabela para estranhos, e um reset como o da primeira causa leva as suas\nlinhas junto.",[10,501,502],{},[42,503,504,508],{},[95,505,507],{"href":506},"\u002Fwebsite-monitoring","Reeve Monitor"," continua verificando de fora:",[254,510,511,514,521,524],{},[257,512,513],{},"a verificação de segurança completa a cada hora, em até três apps",[257,515,516,517,520],{},"uma mensagem quando um resultado ",[42,518,519],{},"muda",", para que uma tabela que abriu depois de uma migração não fique esperando você olhar",[257,522,523],{},"se seu app está no ar",[257,525,526],{},"um relatório mensal, em linguagem simples, do que ele viu",[10,528,529],{},[42,530,531,535],{},[95,532,534],{"href":533},"\u002Fsupabase-backups","Reeve Care"," guarda uma cópia do que há nas suas tabelas:",[254,537,538,541,544,547,550],{},[257,539,540],{},"uma cópia criptografada do seu banco de dados do Supabase num cronograma, no armazenamento próprio da Reeve na UE, fora da sua conta do Supabase",[257,542,543],{},"cada cópia verificada antes de valer, contando as linhas de cada tabela",[257,545,546],{},"também seus arquivos enviados, assim que você conecta uma credencial do Storage",[257,548,549],{},"uma restauração com um clique, com uma cópia de segurança do estado atual feita antes",[257,551,552],{},"tudo o que o Monitor faz",[47,554,556],{"id":555},"o-que-fazer-agora","O que fazer agora",[558,559,560],"key-takeaways",{},[254,561,562,568,577,580,583,586],{},[257,563,564,565,567],{},"Rode a consulta de verificação no SQL Editor. Cada função que disser ",[14,566,181],{}," é uma que o seu app perdeu.",[257,569,570,571,574,575,343],{},"Devolva o grant com ",[14,572,573],{},"grant usage on schema public to anon, authenticated, service_role;"," e fique no ",[14,576,378],{},[257,578,579],{},"Se o schema foi apagado, veja se as suas tabelas estão vazias e procure uma cópia feita antes do reset.",[257,581,582],{},"Se aparecer um erro de tabela em seguida, dê a essa tabela o grant, o Row Level Security e uma regra juntos.",[257,584,585],{},"Proteja tabela por tabela, onde dá para ajustar, e deixe o grant do schema em paz.",[257,587,588,589,591],{},"Se o erro veio de uma migração, dê ",[14,590,349],{}," ao usuário de migração e a mais ninguém.",[10,593,594,595,597],{},"Comece pela consulta de verificação, porque um único resultado diz quais funções\ndo seu app perderam o caminho para entrar. Depois, com a porta aberta de novo,\n",[95,596,492],{"href":491}," para ver o que ele entrega a um\nestranho.",{"title":30,"searchDepth":599,"depth":599,"links":600},3,[601,603,604,605,606,607,608,609,610,611],{"id":49,"depth":602,"text":50},2,{"id":136,"depth":602,"text":137},{"id":185,"depth":602,"text":186},{"id":219,"depth":602,"text":220},{"id":279,"depth":602,"text":280},{"id":304,"depth":602,"text":305},{"id":359,"depth":602,"text":360},{"id":449,"depth":602,"text":450},{"id":495,"depth":602,"text":496},{"id":555,"depth":602,"text":556},"Noções de segurança","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcover-1200x630.png","Um pátio murado de tabelas de banco de dados, cada porta aberta e iluminada, atrás de um portão de entrada fechado com as grades baixadas.","Supabase \"permission denied for schema public\" é um grant que falta no schema. O que o removeu, e a linha que o devolve.",false,"md",[619,622,625,628,631],{"q":620,"a":621},"O que significa \"permission denied for schema public\" no Supabase?","Significa que a função que faz a requisição, normalmente anon ou authenticated, não tem o direito de entrar no schema public, então o Postgres recusou antes de olhar qualquer tabela. O erro traz o código 42501 e costuma chegar ao seu app como 401 ou 403. Todo projeto do Supabase começa com esse direito concedido, então o erro significa que alguém ou algo o removeu.",{"q":623,"a":624},"É seguro conceder usage no schema public?","Sim. Todo projeto do Supabase começa exatamente com esse grant. Ele só deixa uma função chegar às tabelas do schema: cada tabela continua precisando do próprio grant, e o Row Level Security continua decidindo quais linhas cada visitante recebe. O que merece uma olhada são as tabelas por trás, porque uma com grant para anon e Row Level Security desligado entrega todas as linhas a qualquer um que pedir.",{"q":626,"a":627},"Qual a diferença para \"permission denied for table\"?","O erro de schema para a requisição antes que ela chegue a qualquer tabela, então todas as tabelas do schema falham de uma vez. O erro de tabela é sobre uma única tabela que não tem grant para aquela função, e o resto do seu app continua funcionando. Os dois trazem o código 42501, então o que os diferencia são as palavras da mensagem.",{"q":629,"a":630},"Por que minhas tabelas funcionam no SQL Editor do Supabase e não no meu app?","Porque o SQL Editor executa as suas consultas com a função postgres, que é dona das suas tabelas e não precisa do grant que as funções do seu app perderam. O seu app usa anon para visitantes sem login e authenticated para quem entrou. Pergunte ao Postgres diretamente sobre essas duas funções, com has_schema_privilege, para ver o que o seu app vê.",{"q":632,"a":633},"O que eu deveria proteger no lugar do grant do schema?","As tabelas. Dê a cada tabela um grant só para as funções que precisam dele, ligue o Row Level Security com uma regra em toda tabela e deixe as tabelas novas começarem sem nenhum acesso. O Supabase torna essa última parte o padrão para projetos existentes em 30 de outubro de 2026.","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",[16,636,637,638,639,640,641],"supabase permission denied for schema public","supabase permission denied for schema","grant usage on schema public","postgres 42501 schema public","drop schema public cascade supabase","supabase permissões função anon",{},true,"\u002Fblog\u002Fpermission-denied-for-schema-public","2026-10-18",{"title":5,"description":615},"blog\u002Fpermission-denied-for-schema-public",[649,650,651],"Supabase \"permission denied for schema public\" significa que a função que faz a requisição não tem nenhum direito de entrar no schema public, então o Postgres recusou antes de olhar uma única tabela.","Todo projeto do Supabase começa com esse direito concedido a anon, authenticated e service_role. Se o seu app recebe esse erro, algo o removeu: o schema foi apagado e criado de novo, ou um script revogou o grant.","Devolvê-lo é uma linha de SQL. O grant só deixa uma função chegar às suas tabelas, e o Row Level Security continua decidindo quais linhas cada visitante recebe, então confira essas regras antes de dar o problema por resolvido.","UMTE3pokhn-j1A4n4Nx_nON6jhVVLrtOpCkrIIlk9u4",[654,660,666,672,678,684,690,696,702,708,714,721,727,733,739,745,751,757,763,769,775,781,787,788,794,800,806,812,818,824,830,836,842,848,854,860,866,872,878,884,890,896,902,908,914,920,924,930,936,942,948,954,960,966,972,978,984,990,996,1002,1008,1014,1019,1025,1031,1037,1043,1049,1055,1061,1067,1073,1079,1085,1091,1097,1103,1109,1115,1121,1127,1133,1139,1145,1150,1156,1162,1168,1173,1179],{"path":655,"title":656,"description":657,"published":658,"category":612,"image":659,"draft":616},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": o pooler não tem lugar para mais um cliente. A porta da sua string de conexão define o limite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":661,"title":662,"description":663,"published":664,"category":612,"image":665,"draft":616},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Erro do Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": o Google está desativado no seu projeto Supabase. Como ativar e corrigir o redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":667,"title":668,"description":669,"published":670,"category":612,"image":671,"draft":616},"\u002Fblog\u002Fviolates-foreign-key-constraint","Erro do Supabase \"violates foreign key constraint\" ao inserir","Supabase \"insert or update on table violates foreign key constraint\": sua linha aponta para uma linha que não existe. Qual, por quê, e como corrigir.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":673,"title":674,"description":675,"published":676,"category":612,"image":677,"draft":616},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Erro do Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": uma coluna obrigatória chegou vazia. De onde veio o null, e como corrigir.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":679,"title":680,"description":681,"published":682,"category":612,"image":683,"draft":616},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": para onde foi a sessão","\"Auth session missing!\" é o supabase-js sem achar nenhuma sessão logada e sem chegar a perguntar ao Supabase. Para onde foi a sessão, e a correção.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":685,"title":686,"description":687,"published":688,"category":612,"image":689,"draft":616},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ninguém está logado","\"invalid claim: missing sub claim\": o Supabase Auth recebeu um token autêntico sem nenhum usuário, a chave do projeto no lugar de uma sessão.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":691,"title":692,"description":693,"published":694,"category":612,"image":695,"draft":616},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": a causa real","\"Failed to send a request to the Edge Function\": o navegador não recebeu uma resposta legível. O console dele diz por quê e se a sua função rodou.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":697,"title":698,"description":699,"published":700,"category":612,"image":701,"draft":616},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por que o Supabase redireciona links de e-mail para localhost:3000","Se o Supabase redireciona para localhost:3000, a Site URL nunca foi trocada ou o seu endereço falta em Redirect URLs. A solução, e o curinga a evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":703,"title":704,"description":705,"published":706,"category":612,"image":707,"draft":616},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" num link novo","Num link enviado há um minuto, \"Email link is invalid or has expired\" no Supabase costuma significar que um filtro de e-mail o usou antes. Como resolver.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":709,"title":710,"description":711,"published":712,"category":612,"image":713,"draft":616},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": uma consulta passou do limite do seu papel, 3 segundos para um visitante. Veja antes a política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":715,"title":716,"description":717,"published":718,"category":719,"image":720,"draft":616},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" no Supabase, e o que vai junto","\"Database error deleting user\" no Supabase: seu banco recusou a exclusão. O motivo está nos seus logs, e a correção decide o que mais é apagado.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":722,"title":723,"description":724,"published":725,"category":612,"image":726,"draft":616},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" no Supabase","O webhook do Stripe numa Edge Function do Supabase diz \"No signatures found matching the expected signature\"? São duas causas. Continue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":728,"title":729,"description":730,"published":731,"category":612,"image":732,"draft":616},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" no Supabase: as três causas","O Supabase diz \"Invalid login credentials\" para senha errada, e-mail desconhecido e conta Google. Como saber qual é, e por que é vago.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":734,"title":735,"description":736,"published":737,"category":612,"image":738,"draft":616},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": o erro real","\"Edge Function returned a non-2xx status code\" quer dizer que sua função do Supabase respondeu com um erro. Veja onde ler o erro real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":740,"title":741,"description":742,"published":743,"category":612,"image":744,"draft":616},"\u002Fblog\u002Fcertificate-not-trusted","Certificado não confiável: três causas além do vencimento","Certificado não confiável mesmo com a data certa? Ele cita outro endereço, assinou a si mesmo ou falta um elo na cadeia. Veja como saber qual.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":746,"title":747,"description":748,"published":749,"category":612,"image":750,"draft":616},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": leia as aspas","Supabase \"invalid input syntax for type uuid\": seu app enviou algo que não é um id. Leia as aspas, segure a consulta, mantenha a coluna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":752,"title":753,"description":754,"published":755,"category":612,"image":756,"draft":616},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": o valor já está em uso. Ache a coluna, escolha uma correção e tire o valor da tela.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":758,"title":759,"description":760,"published":761,"category":612,"image":762,"draft":616},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" e a tabela está lá","Supabase \"relation does not exist\" ou PGRST205: nenhuma tabela tem esse nome nesse schema. Quatro verificações, e o que expor um schema abre.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":764,"title":765,"description":766,"published":767,"category":612,"image":768,"draft":616},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" mostra os nomes de argumentos que seu app enviou. Compare-os com a função.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":770,"title":771,"description":772,"published":773,"category":612,"image":774,"draft":616},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" costuma ser um nome que não bate. Quatro verificações e a linha que recarrega.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":776,"title":777,"description":778,"published":779,"category":612,"image":780,"draft":616},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dois limites, um só código","Supabase \"Email Rate Limit Exceeded\" limita cada email que seu projeto envia: 2 por hora no remetente embutido. O que conta e como aumentar.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":782,"title":783,"description":784,"published":785,"category":612,"image":786,"draft":616},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" desconecta seus usuários. Três causas, e como o log do Auth separa cada uma.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":644,"title":5,"description":615,"published":645,"category":612,"image":634,"draft":616},{"path":789,"title":790,"description":791,"published":792,"category":612,"image":793,"draft":616},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": as três coisas que isso significa","Supabase \"Bucket not found\" é uma de três coisas: um link público para um bucket privado, um nome que não bate exatamente ou o projeto errado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":795,"title":796,"description":797,"published":798,"category":612,"image":799,"draft":616},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: qual chave parou de funcionar?","Um erro Supabase invalid JWT é o PGRST301: um token assinado não passou na verificação. Num projeto novo isso é a sessão, não a chave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":801,"title":802,"description":803,"published":804,"category":612,"image":805,"draft":616},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" quase sempre é nenhuma","O Supabase devolve PGRST116, \"JSON object requested, multiple (or no) rows returned\", quando a consulta não achou nada. Linha escondida parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":807,"title":808,"description":809,"published":810,"category":612,"image":811,"draft":616},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" no Supabase: onde olhar","\"Database error saving new user\" quer dizer que algo preso ao seu cadastro no Supabase falhou e tudo foi desfeito. O erro real está nos seus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":813,"title":814,"description":815,"published":816,"category":612,"image":817,"draft":616},"\u002Fblog\u002Fwhat-is-supabase","O que é Supabase? O banco de dados que seu builder escolheu","O que é Supabase: o banco de dados, o login e o armazenamento de arquivos do seu app. O Supabase cuida dos servidores; as regras das suas linhas são suas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":819,"title":820,"description":821,"published":822,"category":612,"image":823,"draft":616},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Uma chave AWS exposta no seu frontend não é como uma chave OpenAI","Uma chave de acesso da AWS exposta no seu frontend lê e grava no seu armazenamento. A solução costuma ser uma presigned URL, não uma chave nova.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":825,"title":826,"description":827,"published":828,"category":612,"image":829,"draft":616},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" ao enviar","\"New row violates row-level security policy for table objects\" quer dizer que o seu envio não tem regra insert. Deixar o bucket público não cria nenhuma.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":831,"title":832,"description":833,"published":834,"category":612,"image":835,"draft":616},"\u002Fblog\u002Fbase44-security-scan","Scan de segurança do Base44: o que só ele enxerga","O scan de segurança do Base44 verifica sete tipos de problema por dentro. Esta é a metade que ele lê e mais ninguém, e a metade que ele nunca olha.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":837,"title":838,"description":839,"published":840,"category":612,"image":841,"draft":616},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Sua chave de API vazou. A ordem em que agir","Uma chave de API vazou e você não sabe o que fazer primeiro. Nem toda chave no seu frontend é um vazamento, e a ordem importa mais que a pressa.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":843,"title":844,"description":845,"published":846,"category":612,"image":847,"draft":616},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sem desligar o RLS","\"Infinite recursion detected in policy for relation\" significa que a sua policy perguntou à tabela que ela protege. Veja como quebrar o círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":849,"title":850,"description":851,"published":852,"category":612,"image":853,"draft":616},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" no Supabase, e a correção errada","\"No API key found in request\" significa que sua requisição chegou ao Supabase sem chave. Quase toda resposta aponta para as regras do seu banco.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":855,"title":856,"description":857,"published":858,"category":612,"image":859,"draft":616},"\u002Fblog\u002Fis-base44-safe","O Base44 é seguro? O que vimos em 5.442 apps Base44","O Base44 é seguro? Rodamos nove verificações em 5.442 apps Base44 no ar. Quase todas tiraram B por motivos que o dono nunca escolheu.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":861,"title":862,"description":863,"published":864,"category":612,"image":865,"draft":616},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Esconder uma chave de API: mova para uma Edge Function do Supabase","Esconder uma chave de API é tirá-la do navegador, e uma Edge Function do Supabase é o menor lugar para guardá-la. Dois passos em volta pesam mais.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":867,"title":868,"description":869,"published":870,"category":612,"image":871,"draft":616},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Seu arquivo .env está exposto? Os doze caminhos para testar","Seu arquivo .env está exposto no seu próprio servidor web? Doze endereços dizem isso em um minuto, e um acerto significa que tudo nele já é público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":873,"title":874,"description":875,"published":876,"category":612,"image":877,"draft":616},"\u002Fblog\u002Fis-v0-safe","Segurança do v0: os 1.790 aplicativos v0 escaneados tiraram A","A segurança do v0 medida em 1.790 aplicativos v0 no ar: todos tiraram A. Só 17 citavam um banco de dados, e é sobretudo isso que esse A mede.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":879,"title":880,"description":881,"published":882,"category":612,"image":883,"draft":616},"\u002Fblog\u002Fis-bolt-safe","O Bolt é seguro? O que vimos em 1.123 aplicativos Bolt","O Bolt é seguro? Passamos 1.123 aplicativos Bolt no ar por nove verificações. A hospedagem saiu limpa. Os achados: chaves e tabelas abertas nos aplicativos.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":885,"title":886,"description":887,"published":888,"category":612,"image":889,"draft":616},"\u002Fblog\u002Fis-supabase-down-or-your-app","O Supabase caiu ou o problema é o seu app? Como saber","O Supabase caiu ou o problema é o seu app? Um projeto pausado, um banco cheio e um erro seu parecem iguais. Quatro verificações separam os casos.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":891,"title":892,"description":893,"published":894,"category":612,"image":895,"draft":616},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","O Supabase criptografa meus dados? Sim. Veja o que isso impede","O Supabase criptografa os dados? Sim: AES-256 em repouso, TLS em trânsito, SOC 2 e ISO 27001. O que cada um cobre, e o vazamento que nenhum deles impede.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":897,"title":898,"description":899,"published":900,"category":612,"image":901,"draft":616},"\u002Fblog\u002Fsupabase-free-plan-limits","O Supabase é gratuito? Sim, com estes limites e sem backups","Sim: o plano gratuito do Supabase vai até 500 MB de banco e 5 GB de egress, sem nenhum backup. O que para em cada limite e o que muda no Pro de $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":903,"title":904,"description":905,"published":906,"category":719,"image":907,"draft":616},"\u002Fblog\u002Ftest-your-supabase-backup","Teste o backup do seu Supabase antes do dia em que precisar","Como testar o backup do seu Supabase: restaurar num projeto de teste, contar as linhas, entrar e procurar a linha que falta num arquivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":909,"title":910,"description":911,"published":912,"category":719,"image":913,"draft":616},"\u002Fblog\u002Fsupabase-backup-github-action","Backup grátis do Supabase com uma GitHub Action, e a pegadinha","Um backup do Supabase com GitHub Action é grátis e serve para muitos apps. O workflow, a connection string certa e o egress de cada execução.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":915,"title":916,"description":917,"published":918,"category":719,"image":919,"draft":616},"\u002Fblog\u002Fdownload-your-supabase-backup","Por que você não consegue baixar seu backup do Supabase","Você não consegue baixar seu backup do Supabase num projeto atual, porque a cópia diária é um snapshot físico. Como conferir e como ter uma cópia só sua.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":107,"title":921,"description":922,"published":918,"category":612,"image":923,"draft":616},"Supabase \"permission denied for table\": o grant que falta","A partir de 30 de outubro, uma tabela nova no Supabase responde \"permission denied for table\" até receber um grant. O e-mail mostra só metade.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":925,"title":926,"description":927,"published":928,"category":612,"image":929,"draft":616},"\u002Fblog\u002Fopen-api-endpoint-exposed","Um endpoint de API aberto é um problema? Leia o JSON","Seu scan apontou um endpoint de API aberto. Se isso importa depende do que voltou, e a maioria dos que encontramos era da própria plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":931,"title":932,"description":933,"published":934,"category":612,"image":935,"draft":616},"\u002Fblog\u002Flovable-security-scan","Escaneamento de segurança do Lovable: o que ele não prova","Escaneamento de segurança do Lovable: o que o Quick scan e o Deep scan checam, quando cada um roda, e a única coisa que nenhum escaneamento por dentro prova.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":937,"title":938,"description":939,"published":940,"category":719,"image":941,"draft":616},"\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","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":943,"title":944,"description":945,"published":946,"category":612,"image":947,"draft":616},"\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":949,"title":950,"description":951,"published":952,"category":612,"image":953,"draft":616},"\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":955,"title":956,"description":957,"published":958,"category":612,"image":959,"draft":616},"\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":961,"title":962,"description":963,"published":964,"category":612,"image":965,"draft":616},"\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":967,"title":968,"description":969,"published":970,"category":612,"image":971,"draft":616},"\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":973,"title":974,"description":975,"published":976,"category":612,"image":977,"draft":616},"\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":979,"title":980,"description":981,"published":982,"category":612,"image":983,"draft":616},"\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":985,"title":986,"description":987,"published":988,"category":612,"image":989,"draft":616},"\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":991,"title":992,"description":993,"published":994,"category":719,"image":995,"draft":616},"\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":997,"title":998,"description":999,"published":1000,"category":719,"image":1001,"draft":616},"\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":1003,"title":1004,"description":1005,"published":1006,"category":719,"image":1007,"draft":616},"\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":1009,"title":1010,"description":1011,"published":1012,"category":612,"image":1013,"draft":616},"\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":472,"title":1015,"description":1016,"published":1017,"category":612,"image":1018,"draft":616},"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":1020,"title":1021,"description":1022,"published":1023,"category":612,"image":1024,"draft":616},"\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":1026,"title":1027,"description":1028,"published":1029,"category":612,"image":1030,"draft":616},"\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":1032,"title":1033,"description":1034,"published":1035,"category":612,"image":1036,"draft":616},"\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. Oito ferramentas comparadas, com preços.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1038,"title":1039,"description":1040,"published":1041,"category":612,"image":1042,"draft":616},"\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":1044,"title":1045,"description":1046,"published":1047,"category":612,"image":1048,"draft":616},"\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":1050,"title":1051,"description":1052,"published":1053,"category":612,"image":1054,"draft":616},"\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":1056,"title":1057,"description":1058,"published":1059,"category":612,"image":1060,"draft":616},"\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":1062,"title":1063,"description":1064,"published":1065,"category":612,"image":1066,"draft":616},"\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":1068,"title":1069,"description":1070,"published":1071,"category":719,"image":1072,"draft":616},"\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":1074,"title":1075,"description":1076,"published":1077,"category":612,"image":1078,"draft":616},"\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":1080,"title":1081,"description":1082,"published":1083,"category":719,"image":1084,"draft":616},"\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":1086,"title":1087,"description":1088,"published":1089,"category":612,"image":1090,"draft":616},"\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":1092,"title":1093,"description":1094,"published":1095,"category":612,"image":1096,"draft":616},"\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":1098,"title":1099,"description":1100,"published":1101,"category":612,"image":1102,"draft":616},"\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":1104,"title":1105,"description":1106,"published":1107,"category":612,"image":1108,"draft":616},"\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":1110,"title":1111,"description":1112,"published":1113,"category":719,"image":1114,"draft":616},"\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":1116,"title":1117,"description":1118,"published":1119,"category":719,"image":1120,"draft":616},"\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":1122,"title":1123,"description":1124,"published":1125,"category":612,"image":1126,"draft":616},"\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":1128,"title":1129,"description":1130,"published":1131,"category":612,"image":1132,"draft":616},"\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":1134,"title":1135,"description":1136,"published":1137,"category":719,"image":1138,"draft":616},"\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":1140,"title":1141,"description":1142,"published":1143,"category":612,"image":1144,"draft":616},"\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":1146,"title":1147,"description":1148,"published":1143,"category":612,"image":1149,"draft":616},"\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":1151,"title":1152,"description":1153,"published":1154,"category":612,"image":1155,"draft":616},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: é a mesma coisa que a anon key?","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":1157,"title":1158,"description":1159,"published":1160,"category":719,"image":1161,"draft":616},"\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":1163,"title":1164,"description":1165,"published":1166,"category":612,"image":1167,"draft":616},"\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":1169,"title":1170,"description":1171,"published":1166,"category":719,"image":1172,"draft":616},"\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":1174,"title":1175,"description":1176,"published":1177,"category":719,"image":1178,"draft":616},"\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":1180,"title":1181,"description":1182,"published":1177,"category":612,"image":1183,"draft":616},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","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",1794213649200]