Markdown é a fonte, HTML é derivado: sanitização com uma borda só
28 de julho de 2026 · Time Orion
Todo sistema que aceita texto formatado de um humano e o exibe como HTML enfrenta a mesma decisão: onde sanitizar?
Existem duas escolas. Sanitizar na leitura (guarda o original, limpa toda vez que exibe) e sanitizar na escrita (limpa uma vez, guarda o resultado limpo).
Escolhemos a segunda, e a decisão vem com uma regra que é mais importante que a escolha em si.
Como funciona no nosso blog
O autor escreve Markdown. No momento de salvar, o servidor converte para HTML e passa por uma allowlist estrita. As duas versões ficam no banco: o Markdown, que é a fonte editável, e o HTML, que é o derivado servido.
O site público consome o HTML e injeta direto na página. Sem sanitizar de novo.
Essa última frase costuma causar desconforto, então vale explicá-la.
Por que não sanitizar de novo
Parece que sanitizar duas vezes é mais seguro. Não é — é mais frágil, por dois motivos.
Primeiro: duas allowlists divergem. No dia em que alguém adiciona uma tag na origem e esquece do consumidor, o conteúdo legítimo quebra silenciosamente. No dia em que o consumidor é mais permissivo que a origem, a segunda passada não acrescenta nada. Uma das duas está sempre errada, e ninguém sabe qual.
Segundo, e mais importante: duas bordas significam nenhuma dona. Quando a responsabilidade é compartilhada, cada lado presume que o outro cuidou. É assim que se cria um terceiro consumidor — um app, um feed, uma API — que esquece de sanitizar porque "isso já vem limpo".
A regra que adotamos é explícita e está escrita no código:
O HTML que sai do save é confiável. A borda é uma só, e é aqui.
Se algum dia um consumidor novo aparecer, ele herda a garantia — em vez de herdar a obrigação.
A allowlist é o produto
Sanitizar não é rodar uma biblioteca: é decidir o que o seu conteúdo pode conter. A nossa é curta de propósito:
- Estrutura: títulos de segundo nível para baixo, parágrafos, listas, citação, tabela, código.
- Ênfase: negrito, itálico, tachado.
- Link e imagem.
E as decisões que valem mais que a lista:
Sem h1. O título do post já é o H1 da página. Um segundo H1 no corpo é erro de semântica e de SEO.
Só https e mailto. javascript: óbvio que não; http: também não, porque link inseguro numa página nossa é aviso de conteúdo misto de graça.
Imagem só com URL absoluta https. Aqui mora uma sutileza que quase passou: a opção de esquemas permitidos da biblioteca filtra URLs que têm esquema. Um caminho relativo não tem — e passava. Foi preciso um filtro explícito para descartar imagem cujo src não começa com https://.
Link externo ganha rel de segurança. Aplicado na transformação, não confiado ao autor.
O que a escolha custa
Seria desonesto não dizer.
Reprocessar exige script. Se a allowlist mudar — ou se a conversão melhorar —, o HTML já gravado continua velho. É preciso um comando que rode o Markdown de novo. Guardar a fonte é o que torna isso possível; é por isso que as duas colunas existem.
A prévia tem que usar o mesmo caminho. Se a tela de prévia renderizar o Markdown de um jeito diferente do save, ela mente. No nosso editor, a prévia chama a mesma função do save — nunca uma renderização client-side "aproximada".
O wrapper que não deve ser reusado
Uma armadilha sutil: já existia no sistema uma sanitização de HTML — a do webmail, que exibe e-mail recebido. Reusá-la teria sido natural.
Teria sido errado. Aquele wrapper é permissivo de propósito: e-mail recebido precisa de fidelidade visual, com estilos e atributos que jamais deveriam entrar num post nosso. São dois problemas com a mesma aparência e requisitos opostos.
Sanitização não é uma função utilitária universal. Ela é específica do contexto — e o contexto é "o que este conteúdo, vindo desta origem, tem o direito de fazer nesta página".
O resumo
Escolha uma borda. Coloque-a onde o conteúdo nasce. Escreva no código que ela é a única, para que o próximo consumidor não invente a segunda. E desconfie de reusar a allowlist de outro contexto — a semelhança é aparente.
O mesmo princípio de fronteira única aparece no gate de aprovação da Aura: um caminho, auditado, para a coisa perigosa virar registro.