Uma landing page criada por IA pode funcionar no preview e falhar assim que o formulário chama uma API em outro domínio. O console mostra um erro de CORS, alguém adiciona * no servidor e a requisição passa — mas a política pode ter ficado mais ampla do que a integração exige.

Validar CORS é reproduzir a troca que o navegador realmente faz: origem exata, método, headers, preflight, credenciais e resposta. Também é reconhecer o limite do mecanismo. CORS controla se o JavaScript de uma origem pode ler determinada resposta; não autentica a pessoa, não impede chamadas fora do navegador e não substitui autorização no backend.

Este guia organiza o teste entre a página publicada e o serviço que recebe a requisição.

Identifique as duas origens

Uma origem combina scheme, host e porta. Estes endereços têm origens diferentes:

https://campanha.exemplo.com
https://api.exemplo.com
https://campanha.exemplo.com:8443
http://campanha.exemplo.com

Caminhos não mudam a origem. Portas e protocolo mudam.

Registre o fluxo antes de editar headers:

origem da landing publicada:
origens de preview realmente usadas:
endpoint da API:
método:
headers enviados:
content type:
credenciais incluídas:
resposta que o JavaScript precisa ler:
responsável pelo servidor:

Se o Site usa o endereço padrão e um domínio próprio, não coloque os dois na allowlist por reflexo. Autorize apenas os hostnames que realmente executam a integração e teste cada um separadamente.

Entenda quem configura CORS

CORS é expresso por headers na resposta do servidor que recebe a chamada. A documentação da MDN descreve o mecanismo que permite ao servidor indicar quais origens podem ler recursos e como o navegador faz uma requisição de preflight antes de certas chamadas.

Isso define uma divisão clara:

  • o frontend escolhe URL, método, headers e política de credenciais;
  • o navegador envia Origin e, quando necessário, OPTIONS;
  • o servidor da API decide quais origens, métodos e headers aceita;
  • o navegador libera ou bloqueia a resposta para o JavaScript.

Adicionar mode: "no-cors" não corrige a API. Esse modo produz uma resposta opaca que o JavaScript não consegue ler e restringe o que pode ser enviado. Corrija o contrato no servidor responsável.

O Site no Ar publica o pacote estático da landing page. A documentação de Publicação não cria uma API de formulário nem configura CORS no serviço externo. O proprietário do endpoint precisa participar da correção.

Descubra se haverá preflight

Algumas requisições consideradas simples podem seguir diretamente. Outras exigem que o navegador envie OPTIONS antes da chamada real.

Um POST com JSON normalmente provoca preflight porque application/json não é um dos content types simples. Um header Authorization ou um header personalizado também costuma provocar essa etapa.

No preflight, o navegador informa a origem, o método pretendido e os nomes dos headers:

OPTIONS /leads HTTP/1.1
Origin: https://campanha.exemplo.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type

Uma resposta compatível pode declarar:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://campanha.exemplo.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Vary: Origin

O preflight não envia o corpo do formulário. Ele verifica se a chamada planejada é permitida. A resposta real ainda precisa trazer os headers CORS adequados.

Reproduza a troca com a origem exata

Teste o preflight sem credenciais reais e com o mesmo método e headers da página:

Terminal window
curl -sS -D - -o /dev/null -X OPTIONS \
-H 'Origin: https://campanha.exemplo.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type' \
https://api.exemplo.com/leads

Depois confira:

  • status retornado pelo OPTIONS;
  • Access-Control-Allow-Origin igual à origem testada;
  • método presente em Access-Control-Allow-Methods;
  • headers necessários em Access-Control-Allow-Headers;
  • política aplicada também a respostas de erro;
  • Vary: Origin quando a resposta varia por origem e passa por cache.

Um curl sem Origin não reproduz a requisição do navegador. Um teste feito apenas com a origem local também não prova que o domínio publicado está autorizado.

Use credenciais somente quando o contrato exige

Por padrão, fetch() cross-origin não inclui cookies. Quando a integração realmente depende de sessão, o frontend pode pedir credentials: "include", mas o servidor precisa responder de forma compatível.

Para uma chamada com credenciais:

  • Access-Control-Allow-Origin precisa trazer uma origem explícita, não *;
  • Access-Control-Allow-Credentials: true precisa estar presente;
  • cookies continuam sujeitos a atributos como SameSite e Secure;
  • autenticação e autorização precisam ser verificadas no servidor;
  • a proteção contra CSRF continua sendo uma decisão separada.

A MDN destaca que wildcards não são válidos para os campos CORS relevantes de respostas com credenciais. Trocar uma origem explícita por * para eliminar um erro cria um contrato diferente e ainda falha no navegador quando cookies estão envolvidos.

Se a landing envia um lead a um endpoint público sem sessão, não habilite credenciais por hábito. Defina proteção contra abuso, validação e limites no backend de acordo com o caso.

Não reflita qualquer Origin

Alguns servidores copiam o valor recebido em Origin para Access-Control-Allow-Origin. Esse padrão só é seguro quando o valor foi comparado com uma allowlist controlada.

Evite:

  • refletir qualquer origem;
  • aceitar sufixos com comparação textual ingênua;
  • confiar em null sem um caso documentado;
  • liberar todos os métodos e headers;
  • permitir origens de preview antigas indefinidamente;
  • manter localhost na configuração de produção.

Normalize e compare origens completas. https://campanha.exemplo.com.atacante.test não pertence a exemplo.com, apesar de conter o texto esperado.

Quando houver múltiplos domínios autorizados, devolva a origem exata que passou na allowlist e inclua Vary: Origin para caches não reutilizarem a resposta entre origens diferentes.

Teste sucesso, erro e redirecionamento

Uma integração pode passar no caminho feliz e falhar quando mais importa. Verifique:

Cenário Evidência esperada
preflight permitido OPTIONS aceita origem, método e headers
origem não autorizada navegador não libera a resposta
validação inválida resposta 4xx continua com CORS para o frontend ler
erro do serviço resposta não expõe detalhes internos
rate limit frontend reconhece o status sem confirmação falsa
redirecionamento destino final mantém contrato compatível
domínio próprio origem final funciona sem depender do preview
credencial ausente backend rejeita conforme o contrato, não por acaso CORS

Headers adicionados apenas a respostas 2xx deixam o formulário sem acesso ao corpo de erro. A pessoa vê uma mensagem genérica de rede quando a API tentou devolver uma validação útil.

Use o navegador como prova funcional

O curl inspeciona a conversa HTTP, mas não aplica todas as decisões do navegador. Na URL publicada:

  1. abra DevTools em uma sessão limpa;
  2. envie apenas dados sintéticos autorizados;
  3. localize OPTIONS e a requisição real no painel Network;
  4. confira Origin, método, request headers e response headers;
  5. confirme que o JavaScript consegue ler sucesso e erro;
  6. repita no endereço padrão e no domínio próprio que permanecerão ativos;
  7. teste uma origem não autorizada;
  8. registre URL, commit, endpoint e resultado.

O guia de testes de formulário amplia a verificação para validação, consentimento, estados e confirmação no sistema receptor.

CORS não protege o endpoint sozinho

Uma chamada bloqueada pelo navegador ainda pode ser feita por servidor, script ou cliente HTTP. O backend precisa validar entrada, autenticar quando necessário, autorizar operações e limitar abuso independentemente de CORS.

Também não envie chave privada no JavaScript para “proteger” um endpoint público. Qualquer pessoa pode inspecionar o bundle e as requisições. O guia para evitar chaves no frontend explica como separar configuração pública de credenciais privadas.

Para scripts ou stylesheets externos usados com SRI, valide CORS com a origem real da página. O artigo de Subresource Integrity detalha esse caso, em que a resposta da CDN precisa permitir a verificação cross-origin.

Prompt copiável para o agente

Valide o contrato CORS desta landing page sem ampliar permissões.
Origem publicada: [scheme + host + porta]
Origens adicionais autorizadas: [lista]
Endpoint: [URL]
Método: [método]
Headers enviados: [lista]
Credenciais: [omit ou include]
- Mostre se a chamada exige preflight.
- Reproduza OPTIONS com Origin, método e headers exatos.
- Confira respostas de sucesso, validação e erro.
- Não use wildcard com credenciais.
- Não reflita Origin sem allowlist.
- Não adicione mode no-cors como correção.
- Diferencie erro CORS, autenticação, autorização e falha de rede.
- Teste no navegador a URL publicada e uma origem rejeitada.
- Devolva headers observados, mudança proposta e evidências.

Checklist final

  • origem da página registrada com scheme, host e porta;
  • endpoint, método e headers inventariados;
  • necessidade de preflight confirmada;
  • OPTIONS testado com Origin real;
  • allow-origin usa o menor escopo necessário;
  • métodos e headers permitidos são explícitos;
  • credenciais só estão ativas quando exigidas;
  • respostas 2xx, 4xx e 5xx foram verificadas;
  • cache varia por origem quando necessário;
  • origem não autorizada foi rejeitada;
  • autenticação, autorização e CSRF foram tratados separadamente;
  • URL publicada passou no navegador com dados sintéticos.

CORS deixa de ser uma tentativa de apagar erros do console quando cada lado do contrato está explícito. A landing sabe o que envia, a API sabe qual origem aceita e o navegador confirma que aquela resposta pode ser entregue ao código certo — sem abrir acesso além do necessário.