14 de jan. de 2026·8 min de leitura

Downloads seguros com URLs assinadas: um guia prático

Downloads seguros com URLs assinadas: evite path traversal, force tipos de conteúdo seguros e expire links para que arquivos privados realmente permaneçam privados.

Downloads seguros com URLs assinadas: um guia prático

Por que downloads privados acabam ficando públicos por acidente

A maioria dos “downloads privados” começa com uma ideia simples: colocar um arquivo num servidor, adicionar uma rota como /download?file=... e confiar que o app só mostrará o botão para usuários logados. O problema é que os arquivos não são baixados pelo botão — são baixados de um endereço que pode ser copiado, compartilhado, adivinhado ou acessado por um script.

Uma falha comum é servir um arquivo privado do mesmo jeito que você serve uma página pública. Se a URL de download funciona sem verificações rigorosas sempre que é requisitada, não importa onde ela foi mostrada. Qualquer um pode chamar o endpoint diretamente, e o app pode retornar o arquivo.

“URLs ocultas” não são proteção. Nomes de arquivo aleatórios e caminhos longos só atrasam adivinhações casuais. Eles não impedem:

  • Um usuário compartilhando o link com outra pessoa
  • Histórico do navegador, logs, screenshots ou tickets de suporte vazando a URL
  • Bots escaneando padrões previsíveis (como /uploads/ ou /invoices/)
  • Um bug expondo listagem de diretório ou permitindo truques com ../

Endpoints de download são alvos interessantes porque frequentemente tocam dados sensíveis (faturas, contratos, exports) e porque são fáceis de testar: envie requisições, veja o que volta, repita. Se o endpoint aceita um nome de arquivo vindo da requisição, um atacante pode sondar por arquivos de outros usuários ou tentar path traversal para escapar da pasta intencional.

Signed URLs mudam as regras fazendo a própria URL carregar a prova de que foi emitida pelo seu servidor para um propósito específico. Uma signed URL apropriada normalmente vincula qual arquivo é permitido, quais permissões se aplicam (às vezes via usuário ou tenant) e por quanto tempo o link deve funcionar.

Signed URLs ainda não são mágicas. Não consertam um modelo de autorização quebrado, e não ajudam se seu servidor assina “qualquer caminho que o usuário pedir”. Também não impedem alguém de compartilhar um link enquanto ele estiver válido.

Um exemplo simples: um agente de suporte copia a URL de download de uma fatura de uma ferramenta administrativa e cola em um chat. Se essa URL for apenas “com cara de secreta”, ela pode funcionar para sempre e virar um endpoint público permanente. Se for um link assinado, expirando e atrelado àquela fatura, é mais difícil de ser usado indevidamente e ele para de funcionar após uma janela curta.

Signed URLs, explicadas sem jargão

Uma signed URL é um link de download normal com uma “prova” extra anexada. A prova é uma assinatura: uma string curta que seu servidor cria usando uma chave secreta que só o servidor conhece.

Quando alguém clica no link, o servidor consegue dizer se a URL foi emitida pela sua aplicação ou se foi adulterada. Essa é a ideia central.

O que é realmente assinado?

A assinatura é calculada sobre alguns valores específicos, transformados em uma única mensagem e então “selados” com sua chave secreta. Um download assinado típico inclui:

  • O identificador do arquivo (não um caminho de arquivo bruto)
  • Um tempo de expiração (um timestamp)
  • Contexto opcional como ID do usuário, ID do tenant ou ação pretendida (download)
  • Às vezes o método HTTP (GET) para que a assinatura não seja reutilizada para outras requisições

Se qualquer uma dessas partes mudar, a assinatura não bate.

A expiração importa porque links vazam. Pessoas os encaminham, o histórico do navegador os armazena, logs os capturam e screenshots acontecem. Links de download expiráveis limitam o raio de dano quando esse vazamento é inevitável.

O que o servidor verifica antes de enviar o arquivo

Quando uma requisição chega, seu servidor repete o mesmo cálculo de assinatura usando os valores na requisição. Se a assinatura computada bater com a que está na URL, e o timestamp ainda for válido, a requisição passa pelo primeiro portão.

Depois disso, o servidor ainda aplica as permissões reais. Se Alice clica num link para a fatura do Bob, a assinatura pode ser válida, mas Alice ainda deve receber um “não autorizado” porque o arquivo não pertence a ela.

Signed URLs aparecem em algumas formas comuns:

  • Parâmetros de query (fáceis de usar, mais comuns)
  • Headers de Authorization (URLs limpas, mais difíceis de compartilhar)
  • Cookies (úteis para downloads no navegador sem expor tokens na URL)

Um erro comum em código de protótipo é implementar a assinatura “pela metade” (checar só a assinatura, sem checar propriedade). É assim que arquivos privados viram públicos quando um formato de URL é descoberto.

Previna path traversal não confiando nunca em paths de arquivo

Path traversal ocorre quando um app deixa um usuário influenciar o caminho do arquivo e o usuário usa isso para alcançar arquivos que não deveria ver. O exemplo clássico é ../ (subir uma pasta), mas atacantes raramente param por aí. Eles tentam versões codificadas como %2e%2e%2f, strings duplamente codificadas, barras invertidas (..\\\\) que funcionam no Windows, ou separadores estranhos que são normalizados mais tarde pelo SO.

Por isso aceitar algo como ?file=reports/2025/invoice.pdf é arriscado. Mesmo checando rapidamente ../, você pode ser queimado pela ordem de decodificação (decodificar uma vez vs duas vezes), barras mistas ou um framework que normaliza o caminho depois da sua validação.

O padrão mais seguro é simples: usuários nunca passam um caminho. Eles passam um ID opaco (ou um token assinado) e o servidor procura a localização real no armazenamento.

Exemplo: em vez de GET /download?file=..., use GET /download?docId=8f31.... No servidor, busque docId no banco, confirme que o requisitante tem permissão, então leia o caminho armazenado exato (ou a chave do objeto) que você criou. O usuário nunca tem chance de “mirar” a chamada de leitura de arquivo.

Se você precisa trabalhar com paths (por exemplo, armazenamento em disco local), normalize e valide antes de qualquer acesso ao arquivo. Uma boa regra é: construa o caminho final a partir de um diretório base conhecido mais um nome relativo conhecido e seguro, então confirme que ele permanece dentro do diretório base após a normalização.

Checagens práticas que seguram melhor do que filtros frágil de strings:

  • Rejeite paths absolutos (os que começam com /, \\\\ ou um prefixo de drive como C:).
  • Decodifique uma vez, normalize, depois valide. Não valide a string bruta.
  • Bloqueie separadores inesperados (mistura de / e \\\\) e bytes nulos.
  • Depois de juntar base + solicitado, confirme que o caminho normalizado começa com a base normalizada.
  • Prefira uma allowlist de chaves de arquivo conhecidas no banco em vez de qualquer nome fornecido pelo usuário.

Muitos handlers de download quebrados erram nisso porque se concentram na parte da signed URL e esquecem que o path ainda é controlado pelo atacante.

Aplique tipos de conteúdo para que arquivos não rodem como páginas web

Signed URLs controlam quem pode buscar um arquivo. Elas não controlam como o navegador trata esse arquivo depois de baixado. Se você servir um upload com headers errados, um “download” pode virar uma página web que roda na sessão do seu usuário.

Uma surpresa comum é o content type sniffing. Mesmo que você envie um tipo genérico, alguns navegadores tentam adivinhar o que é o arquivo. Se o conteúdo parece HTML ou JavaScript, o navegador pode renderizar em vez de baixar. É assim que um upload aparentemente inofensivo vira um script que roda.

Defina os headers corretos toda vez

Faça do endpoint de download o único lugar que define headers. Não confie no que a camada de armazenamento “acha” que o tipo é.

No mínimo, defina estes no response:

  • Content-Type: permita apenas tipos que você espera (por exemplo application/pdf, image/png).
  • Content-Disposition: attachment; filename="...": força o download em vez de renderizar inline.
  • X-Content-Type-Options: nosniff: diz ao navegador para não adivinhar.

Também trate o filename como input não confiável. Se você montar filename a partir de dados do usuário, remova separadores de caminho e caracteres de controle. Mantenha-o simples: letras, números, pontos, traços e underscores. Se precisar do nome “bonito”, armazene-o separadamente da chave de armazenamento.

Bloqueie tipos arriscados e use um padrão seguro

Se usuários podem enviar arquivos, decida o que você nunca vai servir tal como está. HTML, SVG e qualquer coisa parecida com script são de alto risco porque podem executar quando abertos.

Uma política simples que funciona bem:

  • Permita uma lista pequena de tipos de download conhecidos (PDF, imagens comuns, CSV se necessário).
  • Rejeite ou coloque em quarentena text/html, image/svg+xml e quaisquer tipos relacionados a JavaScript.
  • Se o tipo do arquivo estiver ausente ou não bater com sua allowlist, sirva como application/octet-stream.
  • Sempre use Content-Disposition: attachment para arquivos enviados por usuários.

Exemplo concreto: se alguém faz upload de “invoice.html” e você serve com Content-Type: text/html e display inline, abrir o link pode rodar scripts. Se você forçar application/octet-stream junto com attachment, o mesmo arquivo vira um download que não será executado no navegador.

Como assinar e validar URLs com segurança

Get security fixes verified
FixMyMess combines AI tooling with human verification to harden real-world apps.

Uma signed URL só é tão segura quanto o que você assina e o quão estritamente você a valida. O objetivo é simples: o servidor deve poder provar que a requisição foi permitida para um arquivo específico, por um tempo limitado e (se necessário) para um usuário específico, sem confiar em nada que o navegador envie.

Um padrão seguro de assinatura

Mantenha o segredo de assinatura apenas no servidor. Não o envie para o cliente, não o coloque em variáveis de ambiente expostas ao build do navegador e nunca inclua a chave no código. A URL deve carregar apenas dados públicos mais uma assinatura.

Assine um conjunto pequeno e estrito de campos e trate todo o resto como não confiável. Um conjunto prático mínimo é:

  • rid: um resource ID (não um caminho de arquivo)
  • exp: um timestamp de expiração
  • sub: um ID de usuário ou tenant quando downloads são escopados por usuário
  • sig: a assinatura (por exemplo, um HMAC)

No servidor, crie uma string canônica em ordem fixa (por exemplo rid=...\u0026exp=...\u0026sub=...). Então assine exatamente essa string. Ao validar, reconstrua a string canônica a partir dos valores parseados, recalcule a assinatura e compare.

Use comparação em tempo constante para checar a assinatura. Igualdade normal de strings pode vazar pequenas diferenças de tempo que ajudam atacantes a adivinhar uma assinatura por muitas requisições.

Seja rígido ao parsear. Se um campo estiver faltando, duplicado, malformado ou fora do intervalo, rejeite a requisição. Também rejeite quaisquer parâmetros extras que você não assinou. Caso contrário alguém pode anexar \u0026role=admin ou \u0026download=true e enganar código downstream que lê esses valores.

Aqui está a forma da lógica de validação (language-agnostic):

allowed = {rid, exp, sub, sig, kid}
if any query key not in allowed: reject
parse rid, exp, sub (strict types)
if now \u003e exp: reject
canonical = "rid=...\u0026exp=...\u0026sub=..."
expected = HMAC(secret_for(kid), canonical)
if !constant_time_equals(sig, expected): reject
serve file for rid (after authz check)

Por fim, planeje rotação de chaves. Adicione um pequeno kid (key id) para poder manter uma chave antiga por um breve período enquanto novas links usam a chave nova. Links antigos devem expirar rápido de qualquer modo, então você não será forçado a suportar chaves antigas por muito tempo.

Um signed URL expirando só é útil se a expiração coincidir com o que o usuário precisa fazer. Muito curta e você cria tickets de suporte. Muito longa e você cria uma porta dos fundos silenciosa: um arquivo “privado” que continua compartilhável por dias.

Uma regra simples: ajuste a expiração para a janela mais curta que ainda se encaixe na tarefa. Visualizar um documento agora pode precisar de 5 a 15 minutos. Download de um export grande pode precisar de 30 a 60 minutos. Se a ação puder ser retomada depois, gere um link novo depois que o usuário fizer login novamente.

Links de uso único reduzem risco de compartilhamento, mas podem quebrar fluxos reais (trocar de app no mobile, Wi-Fi instável, gerenciadores de download que re-tentam). Links reutilizáveis são mais amigáveis, mas precisam de controles mais rígidos.

Opções práticas que costumam funcionar:

  • Link reutilizável de curta duração para downloads normais.
  • Link one-time para arquivos altamente sensíveis (folha de pagamento, chaves privadas, documentos legais).
  • Link reutilizável com limite de downloads (por exemplo, máximo de 3 downloads bem-sucedidos).
  • Link reutilizável escopado a um usuário ou organização (assinatura inclui userId/orgId e fileId).
  • Link reutilizável escopado à sessão quando for necessário “deve estar logado”.

Para reduzir abuso, adicione rate limits no endpoint que valida a assinatura. Mesmo que a URL esteja assinada, ela pode ser bombardeada. Coloque um teto de requisições por IP e por usuário, e considere bloquear após falhas repetidas (assinaturas inválidas, timestamps expirados).

Logging importa para auditorias, mas mantenha-o mínimo. Armazene fileId, userId/orgId, timestamp e resultado (sucesso/negado). Evite logar a URL completa ou a query string pois pode conter a assinatura.

Exemplo: um app de faturamento pode emitir um link assinado de 15 minutos para um PDF de fatura, escopando ao orgId do cliente. Se um link vazar para um fornecedor, ele falha porque o orgId não bate. Se o usuário precisar amanhã, pede um link novo depois de fazer login.

Passo a passo: construir um fluxo de download seguro

Check your downloads now
We will review your download routes for auth gaps, traversal risk, and unsafe headers.

Mantenha seus arquivos privados por padrão. Coloque-os em um armazenamento que não seja servido diretamente pelo seu servidor web ou CDN como pasta pública. Trate downloads como uma ação que seu app executa, não como um arquivo estático que qualquer um pode adivinhar.

Aqui está um fluxo simples que se sustenta em apps reais:

  1. Armazene arquivos de forma privada, com IDs: Salve cada arquivo com uma chave interna aleatória (ou ID no banco), não um nome fornecido pelo usuário como ../../secret.env. Mantenha o filename original apenas como metadado de exibição.
  2. Usuário pede um download: Ele chama um endpoint como GET /downloads/:fileId estando logado.
  3. Cheque permissão primeiro: Busque o registro do arquivo e confirme que o usuário atual pode acessá-lo (proprietário, membro do time, plano pago, o que forem suas regras).
  4. Gere uma signed URL de curta duração: Crie uma URL que inclua fileId, um timestamp de expiração e uma assinatura (HMAC). Faça-a válida por minutos, não dias.
  5. Redirecione ou retorne a signed URL: O cliente então requisita a signed URL para efetivamente receber os bytes.

Quando o endpoint da signed URL recebe uma requisição, seja rígido antes de tocar qualquer dado do arquivo. Verifique a assinatura e a expiração primeiro. Então carregue o arquivo pela sua chave interna, nunca por um path bruto enviado pelo cliente. Finalmente, faça stream do arquivo para o usuário para que downloads grandes não encham a memória do servidor.

Uma boa resposta de download também define headers seguros. Force o download com Content-Disposition: attachment e defina Content-Type a partir de metadados confiáveis (ou uma etapa de detecção no servidor). Não reflita um content type fornecido pelo usuário, porque é assim que endpoints de “download” viram páginas que rodam no navegador.

Para erros, seja útil mas não revelador. Diga “Não encontrado” ou “Link expirado”, mas não inclua paths internos, nomes de buckets ou stack traces.

Erros comuns que transformam signed URLs numa falsa sensação de segurança

Signed URLs podem ser muito seguras, mas somente se você as tratar como uma peça de um controle de acesso maior. A maioria das falhas acontece quando a assinatura está correta, mas o servidor ainda serve o arquivo errado ou o serve de forma arriscada.

Uma armadilha comum é assinar a “string URL completa” exatamente como aparece no navegador. Pequenas mudanças podem quebrar a validação ou criar bypasses: parâmetros de query podem ser reordenados, espaços codificados de formas diferentes, ou um proxy pode adicionar um parâmetro. Se seu código assina uma versão e valida outra, você terá downloads falhos e gambiarras de emergência que enfraquecem a segurança.

Outro erro frequente é deixar o usuário controlar o path do arquivo ou a extensão. Mesmo com uma assinatura válida, você não quer truques com ../, caracteres Unicode inesperados ou uploads com .html passando despercebidos. Uma signed URL geralmente deve apontar para um identificador estável (como um ID interno) e seu servidor deve decidir o caminho real de armazenamento.

A expiração também é onde designs bons silenciosamente falham. Times geram links “temporários” que duram semanas, ou esquecem de checar o timestamp. Isso transforma um arquivo privado num endpoint público de longa duração que pode ser compartilhado, indexado, encaminhado ou raspado.

Finalmente, muitas apps esquecem que downloads são também uma superfície de entrega de conteúdo. Se você servir uploads como text/html (ou permitir que o navegador adivinhe), um arquivo enviado pode rodar como página web. Isso pode levar a takeovers de conta via injeção de script, mesmo que a URL fosse assinada.

Sinais de alerta para ficar de olho

Estes padrões aparecem frequentemente em code reviews:

  • Assinaturas dependem da ordem exata dos parâmetros ou da codificação exata da URL.
  • Usuários podem requisitar paths arbitrários, filenames ou extensões.
  • Expiração está ausente, não é aplicada ou é definida para muito no futuro.
  • Respostas permitem content sniffing ou retornam o tipo de conteúdo errado.
  • Segredos de assinatura aparecem em código cliente, logs ou mensagens de erro verbosas.

Exemplo: proteger downloads de faturas e documentos

Remove path traversal risk
Replace file path parameters with safe IDs and server-side lookups.

Imagine um portal de clientes onde cada conta tem faturas (PDFs) e documentos de verificação de identidade (imagens ou PDFs). Esses arquivos são privados por padrão, mas usuários ainda precisam de um botão simples “Download”.

Um modo comum de falhar é o portal gerar uma URL permanente como /files/1234/invoice.pdf. Alguém a encaminha num chat de grupo e agora qualquer pessoa com o link consegue buscá-la. Pior, mecanismos de busca e ferramentas de logs podem armazená-la, transformando um documento privado em um endpoint semi-público.

Com downloads expirando e assinados, o portal evita expor um endereço estável e adivinhável. Em vez disso, emite um link de curta duração ligado ao arquivo exato e (quando apropriado) ao usuário ou organização atual.

Aqui está um fluxo prático:

  • Usuário clica em “Download invoice” estando logado.
  • O servidor checa: esse usuário é dono da invoice inv_9281?
  • O servidor gera uma signed URL que inclui user_id, file_id e um tempo de expiração.
  • O endpoint de download verifica assinatura e expiração, então busca o arquivo por file_id no storage (não por um path enviado pelo navegador).
  • A resposta força um tipo de conteúdo seguro e comportamento de download (por exemplo, application/pdf mais um filename para download).

As duas proteções quando esse link chega a um chat de grupo são expiração e escopo. A expiração limita o vazamento no tempo. O escopo faz com que o servidor rejeite a requisição a menos que o usuário autenticado (ou org) bata com o que foi assinado. Se você oferecer passwordless por email, pode escopar para uma sessão ou token de uso único. A ideia é a mesma: o link não é uma chave universal.

O suporte eventualmente vai ouvir: “Meu link expirou.” Não resolva isso tornando links válidos por uma semana. Um padrão mais seguro é permitir que o suporte reenvie um link novo depois de verificar o usuário (por exemplo, ele deve estar logado ou confirmar por email).

Checklist rápido e próximos passos

Se você quer que signed URLs realmente protejam arquivos privados, as configurações mais seguras parecem entediantes. Elas fazem as mesmas checagens sempre e nunca confiam em entradas que não foram criadas por elas.

Use esta checklist para revisar seu fluxo de download:

  • Seu endpoint de download aceita um ID estável (como file_id), não um path ou filename fornecido pelo usuário.
  • Você valida assinatura e expiração, e rejeita quaisquer query params inesperados (sem “botões extras” que atacantes podem mexer).
  • Você define Content-Type e Content-Disposition de propósito (por exemplo, force downloads para documentos em vez de deixar o navegador adivinhar).
  • Arquivos vivem em armazenamento privado, seu app usa credenciais com princípio do menor privilégio e mensagens de erro permanecem vagas (sem “arquivo existe”, sem stack traces).
  • Você loga falhas (assinatura inválida, link expirado, acesso negado) para detectar padrões sem vazar detalhes para o usuário.

Uma expectativa simples: se alguém copia um link válido do laptop e cola em outro navegador, ele deve ou continuar válido para o usuário e a janela de tempo pretendida, ou falhar de forma limpa. Nunca deve virar um endpoint público permanente só porque foi compartilhado.

Próximos passos

Se você está endurecendo um sistema existente, comece pequeno e expanda:

  • Escolha um tipo de arquivo sensível (faturas, contratos, exports) e mova-o para trás de um endpoint de download assinado que usa IDs.
  • Adicione validação estrita: assinatura, expiração e uma allowlist de parâmetros permitidos. Depois aplique content-type e headers de download.
  • Faça um rápido teste de abuso: tente strings de path traversal, adicione query params aleatórios, modifique a expiração e confirme que toda tentativa falha com segurança.

Se seu app foi gerado por AI (ferramentas como Lovable, Bolt, v0, Cursor ou Replit), vale a pena auditar rotas de download em particular. FixMyMess foca em diagnosticar e reparar problemas como autorização quebrada, segredos expostos e handlers de download inseguros, e oferece uma auditoria de código gratuita para mapear riscos antes de você começar a mudar.

Perguntas Frequentes

Why does my “private download” still work when I paste the link into another browser?

Um download “privado” vira público quando a URL funciona por si só, sem checar permissões toda vez que é solicitada. Se alguém copia, adivinha ou automatiza essa URL e seu servidor ainda retorna o arquivo, o download é efetivamente público mesmo que o botão só apareça para usuários autenticados.

Aren’t long, unguessable URLs enough to protect downloads?

URLs que parecem aleatórias ajudam um pouco, mas não são segurança. Links são compartilhados, ficam no histórico do navegador, aparecem em logs, são colados em chats de suporte ou descobertos por scanners automatizados. Uma URL estável pode continuar funcionando para sempre se você não aplicar autorização no servidor.

What exactly is a signed URL in plain terms?

Uma signed URL é um link de download normal que inclui uma assinatura que seu servidor verifica usando uma chave secreta. Se alguém alterar o ID do recurso, a data de expiração ou o escopo, a assinatura não bate e a requisição é rejeitada antes de qualquer byte ser enviado.

What should I sign, and what’s the safest way to validate it?

Assine um conjunto pequeno e estrito de campos, como um ID de recurso, um timestamp de expiração e (quando necessário) um escopo de usuário ou organização, e calcule um HMAC sobre uma string canônica em ordem fixa. Na validação, rejeite campos ausentes ou malformados, aplique a expiração, recompute o HMAC e compare usando uma checagem em tempo constante.

When does a download endpoint become vulnerable to path traversal?

Torna-se vulnerável quando o cliente consegue influenciar o caminho no sistema de arquivos, mesmo indiretamente. O padrão mais seguro é aceitar um ID opaco do arquivo, buscar a chave de armazenamento real no servidor, confirmar que o requisitante tem acesso e só então ler ou fazer stream do arquivo.

Why do content-type headers matter if the URL is signed?

Porque você pode acabar servindo um upload como página web. Force o comportamento de download com Content-Disposition: attachment, defina um Content-Type confiável e adicione X-Content-Type-Options: nosniff para que o navegador não tente “adivinhar” e renderizar algo como HTML ou script.

How long should an expiring download link last?

Use a janela mais curta que ainda permita ao usuário completar a ação. Muitas aplicações usam 5–15 minutos para visualização e mais tempo apenas para exports grandes; em vez de manter links compartilháveis por dias, gere um link novo quando o usuário entrar de novo.

Can someone share a signed URL and let others download the file?

Reduzem abusos casuais, mas não impedem que alguém reencaminhe um link válido enquanto ele estiver ativo. Se precisar de controle mais rígido, faça o escopo da assinatura para usuário/org ou sessão e sempre aplique autorização no servidor quando o download for solicitado.

How do I rotate signing keys without breaking active links?

Inclua um pequeno identificador de chave (kid) e mantenha chaves antigas disponíveis apenas por um curto período enquanto os links existentes expiram. Mantenha a expiração curta para não ter que oferecer suporte a chaves antigas por muito tempo e nunca coloque segredos de assinatura no código cliente ou em logs verbosos.

My app was generated by an AI tool—what’s the quickest way to check if downloads are unsafe?

Muitas apps geradas por AI têm rotas de download que apenas “escondem” URLs, aceitam file=... em paths, pulam validações estritas ou retornam headers inseguros. Se você herdou um protótipo que vaza arquivos ou tem lógica de auth confusa, FixMyMess pode executar uma auditoria de código gratuita e depois reparar o fluxo de download rapidamente, incluindo checagens de autorização, validação de signed URL e headers de resposta mais seguros.