Pular para o conteúdo

Noções de segurança

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.

Vlad Tkachenko9 min de leitura
Seis chamadores diferentes alcançam um mesmo servidor, e a mesma resposta volta para cada um deles.

Em resumo

  • Um curinga CORS só é um risco de segurança quando algo privado responde atrás dele. Sozinho, ele permite ler coisas que qualquer pessoa já podia baixar.
  • O cabeçalho é uma instrução para o navegador do seu visitante e chega depois que a resposta já saiu. Ninguém o lê fora de um navegador, então restringi-lo deixa um endpoint aberto exatamente igual.
  • O formato que merece uma noite é um servidor que devolve como eco o site que está perguntando e ainda permite credenciais. Esse deixa outro site ler dados como o seu usuário logado.

Seu scan voltou com uma linha que se lê como um alarme: sua API está aberta para qualquer site. Ou alguém da área técnica olhou o que o seu servidor devolve e disse que o seu aplicativo tem um curinga CORS, que é o caractere *, que aparentemente significa todo mundo.

Aqui está a parte que guia após guia conta errado: o curinga quase nunca é o que abriu a sua API. Ele é uma instrução que o seu servidor anexa às respostas, endereçada aos navegadores de pessoas que estão em outros sites, e chega depois que a resposta já saiu. Restringi-lo impede que a página de outro site leia os seus dados. Não faz nada contra quem os lê sem navegador nenhum.

Um curinga CORS é um risco de segurança?

Sozinho, quase nunca. Vira um no momento em que algo privado responde atrás dele.

O curinga é o valor * num cabeçalho de resposta chamado Access-Control-Allow-Origin, e significa que o código de qualquer site pode ler aquela resposta específica. Isso soa como uma afirmação sobre quem consegue chegar nos seus dados. É uma afirmação sobre quem pode ler o que o seu servidor já mandou.

O endereço que um scan verifica é aquele de onde o seu aplicativo é servido. Na maioria dos builders, esse endereço distribui suas páginas, suas imagens e seu código compilado, e tudo isso vai para cada visitante por design. Um curinga em cima disso concede permissão para ler arquivos que qualquer um já podia baixar abrindo o seu site.

Então o achado é uma pergunta e não um veredicto, e a pergunta é o que está atrás do cabeçalho. Se a resposta é sua página inicial, não aconteceu nada. Se a resposta é uma lista dos seus clientes, essa lista já estava ao alcance de qualquer um que tivesse o endereço.

O que o Access-Control-Allow-Origin realmente faz

Ele diz ao navegador do seu visitante se a página que está na tela pode olhar uma resposta que o seu servidor já mandou.

A ordem é a coisa toda, e ela corre ao contrário de como quase todo mundo imagina. Uma página em algum outro site executa um pedaço de código que pede dados ao seu aplicativo. A requisição sai. Seu servidor a recebe, executa o que tiver que executar e devolve a resposta inteira. Só então o navegador lê o cabeçalho daquela resposta e decide se entrega o conteúdo à página que pediu. O próprio guia de CORS da MDN resume em uma linha: o servidor precisa consentir com Access-Control-Allow-Origin para compartilhar a resposta com o script.

Seus dados saíram do prédio de um jeito ou de outro. O que o cabeçalho decide é se um pedaço específico de código, rodando dentro do navegador de uma pessoa específica, chega a vê-los.

Os dois chamadores recebem uma resposta, porque o servidor a manda antes de qualquer coisa ser verificada. A barreira na faixa de cima é o navegador, e na faixa de baixo não existe navegador nenhum.

O navegador é a única coisa nessa história que lê o cabeçalho. Um script num servidor, uma ferramenta de linha de comando, um raspador, um aplicativo de celular: nenhum deles o consulta, porque ele foi escrito para um navegador e não há navegador envolvido. Eles mandam a mesma requisição, recebem a mesma resposta e leem cada byte dela.

Restringir o CORS não deixa privado um endpoint aberto

Porque o CORS vive dentro dos navegadores, e quem está se servindo dos seus dados não tem motivo para usar um.

Essa é a parte que custa uma tarde. A pessoa vê o achado do curinga, estreita o cabeçalho para o próprio domínio, faz o deploy de novo, escaneia de novo, e o endereço que distribuía linhas de clientes continua distribuindo linhas de clientes. Sempre distribuiu. O único chamador que chegou a parar foi a página web de outra pessoa.

O que alguém tentaCuringa *Só o seu domínioQualquer origem devolvida como eco, credenciais liberadas
Abrir o endereço numa aba do navegadorFuncionaFuncionaFunciona
Ler o endereço por um script ou um terminalFuncionaFuncionaFunciona
A página de outro site lendo o endereçoFuncionaBloqueadoFunciona
Outro site lendo o endereço como o seu usuário logadoBloqueadoBloqueadoFunciona

Leia a última linha duas vezes, porque é onde o conselho genérico desaba. Um curinga puro não pode ser usado para ler dados que pertencem ao seu visitante logado. Os navegadores recusam essa combinação de saída, e o guia de CORS da MDN diz isso diretamente: se uma requisição leva um cookie e a resposta volta com Access-Control-Allow-Origin: *, o navegador bloqueia o acesso à resposta e registra um erro de CORS no console. Ou seja, é justamente o curinga que torna esse ataque específico impossível.

A coluna que de fato entrega os dados de um usuário logado é a terceira, e para isso o servidor precisa escrever o endereço do próprio chamador dentro da sua resposta.

A configuração de CORS que é de fato perigosa

Um servidor que lê o cabeçalho Origin da requisição, escreve esse mesmo valor dentro da própria resposta e manda Access-Control-Allow-Credentials: true junto.

Ninguém se propõe a fazer isso. Acontece no fim de uma tarde tentando fazer um curinga funcionar com requisições autenticadas e descobrindo que ele nunca vai funcionar. Devolver como eco a origem que perguntou parece a saída: todo site que deveria ser permitido é permitido, os erros no console param, a funcionalidade vai ao ar. O que o servidor está dizendo, na verdade, é que quem decide é o chamador, e isso inclui uma página que ninguém escreveu ainda.

Veja o que isso permite. Sua cliente está logada no seu aplicativo, com um cookie de sessão no navegador dela. Em outra aba ela abre um site que não tem nada a ver com você. O código desse site pede à sua API a conta dela. O navegador dela anexa o cookie, porque anexar cookies é o que navegadores fazem. Seu servidor lê uma Origin da qual nunca ouviu falar, carimba essa origem na resposta como permissão e acrescenta que credenciais estão liberadas. O navegador confere, encontra correspondência e entrega os dados da sua cliente a uma página que ela não sabia que estava lendo.

O chamador fornece o nome, e o servidor escreve esse nome no crachá. Quem pergunta está na lista, e é isso que diferencia esse caso de um curinga.

Na nossa varredura de agosto de 2026 isso apareceu em 61 dos 30.926 aplicativos em que a verificação conseguiu uma resposta. Dos três achados de CORS, é o único que alcança dados que estão atrás de um login.

Com que frequência um curinga aparece, e quem decide isso

Na maior parte das vezes, quem decide é o seu builder. Nessa mesma varredura, 5.727 daqueles 30.926 aplicativos mandavam um curinga, e o melhor indicador isolado de que o seu manda é a plataforma que o publicou.

A verificação de CORS registrou pelo menos um achado em 5.418 dos 5.419 aplicativos do Base44 em que obteve resposta, e em 8 dos 18.518 do Lovable. O Replit ficou no meio, com 1.129 de 3.037. Uma diferença tão grande é a cara de um padrão de hospedagem visto de fora: quase total numa plataforma, quase ausente em outra, ao longo de milhares de aplicativos cujos donos nunca combinaram nada entre si.

Três achados distintos compõem a verificação de CORS nos 30.926 aplicativos: um curinga em 5.727 deles, um endereço respondendo com dados e sem login em 3.852, e o formato da origem devolvida como eco em 61. A soma passa da própria verificação, porque muitos aplicativos têm dois dos três. Todo número aqui vem da nossa varredura de 30.998 aplicativos vibe-coded no ar, que publica cada um junto com a base sobre a qual foi medido.

O que você pode mudar em tudo isso se divide do mesmo jeito. O curinga é enviado por quem serve o seu aplicativo, e num aplicativo vibe-coded normalmente é o builder. O que volta quando um estranho pede dados a um dos seus endereços foi decidido dentro do seu aplicativo, por você ou pelo builder que escreve código em seu nome.

Como verificar o seu próprio aplicativo

Duas coisas para olhar, e a segunda é a que decide se algo disso importa.

Seu aplicativo manda um curinga? Abra seu aplicativo no ar, aperte F12 para abrir as ferramentas de desenvolvedor do navegador, clique em Network e recarregue a página. Clique na primeira requisição da lista e leia o painel Response Headers. Uma linha com access-control-allow-origin: * é o achado. Nenhuma linha desse tipo significa que o seu servidor não compartilha nada entre origens com ninguém.

O que responde atrás? Continue na aba Network e recarregue o aplicativo logado, de olho nas requisições que voltam em JSON. Esses são os endereços de onde seu aplicativo busca dados. Copie cada URL, abra uma janela anônima para ficar deslogado e cole uma de cada vez. Tudo que voltar com linhas de verdade, em vez de um erro ou de uma lista vazia, pode ser lido por qualquer pessoa na internet que tenha aquela URL. Isso vale hoje, diga o seu cabeçalho CORS o que disser, e continua valendo depois que você estreitá-lo.

Nosso scan gratuito faz a segunda verificação por você: lê o código do seu aplicativo atrás dos endereços que ele chama, consulta cada um sem login e reporta os que responderam com dados. Leva cerca de 20 segundos e não precisa de conta: escaneie seu aplicativo.

Se o seu aplicativo fala com o Supabase direto do navegador, há um terceiro lugar para olhar, porque as regras de cada tabela decidem quem pode ler quais linhas e ligá-las não é o mesmo que estar protegido.

O que fazer agora

O que fazer

  • Trate um achado de curinga como uma pergunta sobre o que está atrás do cabeçalho. No endereço de onde seu aplicativo é servido, ele normalmente permite ler arquivos que cada visitante baixa de qualquer jeito.
  • Saia da sua conta e abra cada endereço de dados que o seu aplicativo chama. Tudo que devolver linhas de verdade para um navegador deslogado é público para todo mundo, diga o cabeçalho o que disser.
  • Corrija um endereço aberto no próprio endereço: exija login e responda a um estranho com um 401. Estreitar o cabeçalho CORS deixa esse endereço alcançável por tudo, menos pelas páginas web dos outros.
  • Se o seu servidor devolve como eco a origem que perguntou e manda Access-Control-Allow-Credentials: true, troque isso hoje por uma lista dos seus próprios domínios. É o único caso aqui que deixa outro site ler dados como o seu usuário logado.
  • Se o cabeçalho vem da hospedagem do seu builder e você não consegue mudá-lo, gaste o tempo nos endpoints. É lá que estão os seus dados.

O hábito que vale manter é a passada deslogada pelos seus próprios endereços de dados, porque cada funcionalidade nova acrescenta mais um e nada muda na tela quando um deles começa a responder. O Reeve Care roda esse mesmo scan contra seu aplicativo no ar em uma programação e te avisa por e-mail quando um resultado piora: o que ele vigia e quanto custa.

Se você prefere resolver tudo de uma vez, a checklist de segurança de 10 minutos cobre isso ao lado do resto do que um aplicativo recém-lançado costuma deixar aberto, e quais chaves são seguras no seu frontend é a outra metade da pergunta com que as pessoas costumam chegar.

Perguntas frequentes

Meu scan diz que minha API está aberta para qualquer site. Preciso corrigir?

Olhe primeiro o que responde atrás. Um curinga no endereço de onde seu aplicativo é servido costuma permitir a leitura das suas páginas, das suas imagens e do seu código compilado, e tudo isso cada visitante baixa de qualquer jeito. Corrija quando um endereço atrás desse cabeçalho devolver dados de verdade para alguém que não está logado, e corrija nesse endereço, exigindo login.

Restringir o CORS ao meu próprio domínio deixa minha API privada?

Não. CORS é uma regra que os navegadores aplicam a si mesmos, então ela só governa código rodando na página web de outra pessoa. Um script, um comando de terminal ou um raspador mandam a mesma requisição e leem a mesma resposta, porque nenhum deles consulta o cabeçalho. Se um endereço devolve seus dados sem login, ele faz isso para todo mundo, diga o cabeçalho o que disser.

Outro site pode ler os dados dos meus usuários logados por causa de um curinga?

Com um curinga puro, não. Os navegadores recusam essa combinação: o guia de CORS da MDN afirma que, quando uma requisição leva um cookie e a resposta volta com Access-Control-Allow-Origin no curinga, o navegador bloqueia o acesso à resposta e registra um erro de CORS. A versão que de fato funciona é um servidor que devolve como eco a origem que perguntou, junto com Access-Control-Allow-Credentials em true.

Como eu mudo o cabeçalho CORS num aplicativo Lovable ou Base44?

Muitas vezes você não muda, porque o cabeçalho é enviado pela hospedagem em que seu builder publica e vale para todos os aplicativos daquela plataforma. Vale saber disso antes de gastar uma semana no assunto. O que você sempre pode mudar é o que os seus endpoints devolvem para uma requisição sem login, e é aí que a correção pertence de qualquer forma.

Meu scan também apontou endpoints de API abertos. É o mesmo achado?

É outro, e o mais grave dos dois. Um curinga descreve quem pode ler uma resposta. Um endpoint aberto significa que a resposta continha seus dados e chegou sem que ninguém fizesse login. O segundo vale igualmente para um navegador, para um script e para um estranho com a URL, e estreitar seu cabeçalho CORS não muda nada disso.

Escrito por

Vlad Tkachenko

Fundador da Reeve

Passo meus dias olhando apps criados com Lovable, Bolt, v0, Cursor e Replit, e a curta lista de erros que aparecem neles sem parar.

Mais sobre o autor

Leia depois

Não sabe como está o seu próprio app?

Faça um scan gratuito e receba uma nota clara de A a F em cerca de 20 segundos. Sem conta e sem cartão.

Verificar meu app grátis

Verificação externa automatizada, não uma auditoria completa. A ausência de achados não é garantia de segurança.